The core work in the first half of 2018 revolved around three things: upgrading the architecture of back-office systems, building an internal component library from scratch, and improving the engineering pipeline. This is a systematic retrospective on the reasoning behind our technology choices and the real pitfalls we ran into.
H1 Key Project Review
Back-office System: Webpack 3 → 4 Migration + Incremental TypeScript Adoption
At the start of the year I took over a two-year-old back-office system running Webpack 3 + Vue 2.3, with a stable build time of around 45 seconds. I faced two choices: patch it and keep going, or do a thorough engineering upgrade. Considering the team would need to maintain multiple back-office projects in parallel, I chose the latter.
The core win from upgrading to Webpack 4 wasn't the version number itself — it was the mode mechanism and improved Tree Shaking. The biggest hurdle during the migration was plugin-ecosystem compatibility: several Webpack 3 plugins hadn't caught up to 4.x yet, requiring replacements or custom adapters. Build time ultimately dropped from 45s to 12s, driven mainly by two changes:
// webpack.config.js key config
module.exports = {
mode: "production",
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all",
},
},
},
},
};
Adding HardSourceWebpackPlugin for persistent caching and route lazy-loading made the hot-reload experience in development much better.
Incremental TypeScript migration was a longer-term investment. The legacy code was full of any types — there was no way to fix everything at once. The strategy: enforce TS on new modules, gradually cover old modules via allowJs. By end of June, core module coverage was around 60%. The biggest takeaway from this process was realizing the type system isn't a "constraint" — it's a compile-time contract and form of documentation, especially valuable when several people collaborate, since type definitions serve as the best interface spec.
Component Library Construction
The first half of the year saw us kick off an internal shared component library. The goal wasn't to build a new UI framework, but to wrap common business-layer components on top of Element UI: permission buttons, data dictionary selectors, complex search forms, general CRUD tables, etc.
Several key design decisions were made:
- Props-driven, non-invasive to business logic: components only care about UI and data flow; business logic is delegated out via slots and events
- TypeScript type exports: each component also exports type definitions so consumers get full type hints
- Tree-shakeable imports: paired with
babel-plugin-componentto avoid full bundle imports
// Component type export example
export interface CrudTableProps {
columns: ColumnConfig[];
fetchApi: (params: QueryParams) => Promise<PaginatedResult<any>>;
rowKey?: string;
toolbar?: ToolbarConfig[];
}
By end of June, the component library covered 70% of common use cases across 3 back-office projects, cutting new-project setup time by about 40%.
Engineering Improvements
CI Integration
Previously the team deployed by manually running npm run build and then scp-ing to the server — very risky. In the first half of the year we integrated GitLab CI, with a pipeline covering lint → test → build → deploy four stages. Key config:
# .gitlab-ci.yml core pipeline
stages:
- lint
- test
- build
- deploy
lint:
stage: lint
script:
- npm run lint
- npm run type-check
build:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
The deploy step sends DingTalk notifications — failed builds automatically @-mention the relevant developers. Tracing production incidents shifted from "who deployed it?" to "which MR introduced it?".
Code Quality Toolchain
Rolling out ESLint + Prettier took longer than expected — the real friction wasn't the rules themselves, but the cost of reformatting the existing code. The final strategy: enable lint-staged to only check changed files; handle legacy code with a one-off bulk-format PR. Pairing with commitlint to standardize commit messages noticeably improved code review efficiency.
Pitfalls We Hit
1. TypeScript and Vue Compatibility Issues
Vue 2.x's TypeScript support isn't perfect. vue-property-decorator's decorator syntax loses type inference in some scenarios, especially with mixins and provide/inject. The solution: replace mixins with composition-style patterns where possible, and explicitly declare types for provide/inject.
2. Webpack 4 sideEffects Configuration
Debugging why Tree Shaking wasn't working took half a day. The root cause: sideEffects: false wasn't declared in package.json. Adding it reduced bundle size by another 15%. The lesson: upgrading toolchain means you can't just change config files — you also need to check the package.json of your dependencies.
3. Nuxt.js SSR Pitfalls
When we used Nuxt to handle SEO for a content site, window is not defined kept appearing. The root cause was third-party libraries accessing browser APIs at the module's top level. The solution: use process.client guards, or dynamically require them in the mounted hook. This taught me: SSR isn't just swapping frameworks — your entire dependency chain needs to be adapted.
H2 Plans
Technical Depth:
- TypeScript advanced type system: generic constraints, conditional types, template literal types — put them into practice in the component library
- Track React ecosystem: React 16.7 Hooks are worth diving into; planning to validate with an internal project
- Frontend testing: currently only scattered unit tests; goal is to build automated testing for the component library + CI integration
Engineering System:
- Integrate frontend monitoring with Sentry, covering error capture and performance metric reporting
- Micro-frontend research: as back-office systems multiply, evaluate qiankun / single-spa feasibility
- Dockerize build environment to unify the team's Node version and build dependencies
Technical Influence:
- Give 2–3 internal tech talks (Webpack optimization, TypeScript practices)
- Build component library documentation site to lower the onboarding cost for new members
Summary
- Completed Webpack 4 upgrade and incremental TypeScript migration for the back-office system; build efficiency improved 73%
- Launched the business component library, covering common use cases across 3 projects
- Rolled out GitLab CI pipeline and code quality toolchain; said goodbye to manual deployments
- Solved real problems: Vue + TypeScript compatibility, Webpack Tree Shaking, Nuxt SSR, and more
- H2 focus: React validation, testing system, monitoring system, micro-frontend research
