background
As the development cycle of a project gets longer and larger, the packaging speed of a webPack-based project gets longer and longer. If ts + TSX is used, the slow compilation speed in the development environment will be very obvious. The packaging speed of the current project is as follows
Packaging for the first time
2min30s
Single-edit package
15s
There is an urgent need to improve build efficiency
Optimization idea
Refactoring packaged content based on Vite
Advantages:
- Start the development server directly, compile the request module in real time, and package it at the millisecond level
- HMR is naturally supported and the browser only needs to request changes to the module
Disadvantages:
- The current code packaging approach is more intrusive
- React support for the Vite tool may be flawed
Esbuild-loader + Webpack is used
Advantages:
- Can quickly improve the packaging speed
- It is less intrusive to existing packaging projects and can be injected only in the form of plug-ins
Disadvantages:
- The optimization points are not thorough enough, and there is still much room for improvement
- The capability provided by esbuild-Loader itself is weak and may need to be fixed
Optimization scheme
Single compilation speed optimization
Currently, the esbuild-Loader solution is used for optimization
A single optimization is only for the single type with a large proportion of TS TSX
Replace ts-loader babel-loader with esbuild-Loader by introducing the webpackEsBuildPlugin into the WebPack life cycle
Record file change points in advance for the convenience of thermal update verification and optimization later
First time compilation speed optimization
Enable multi-threaded packaging for babel-loader which takes a lot of time for the first time
Use HappyPack to package and split
The esbuild-loader is faulty
Decorators are not supported
Esbuild itself does not support TS decorators
The solution
OneOf uses a single loader for a single file. When returen is false, babel-loader + TS-loader is used to package files.
oneOf: [
{
test: filePath => {
if (!filePath) {
return false;
}
try {
const fileContent = fs.readFileSync(filePath).toString();
return !hasDecorator(fileContent);
} catch (e) {
return false;
}
},
use: [
{
loader: 'esbuild-loader',
options: {
loader: 'tsx',
target: 'es2018',
},
},
],
},
{
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
},
],
Copy the code
Determines whether the input file has a decorator
/ function hasDecorator(fileContent, offset = 0) {const atPosition = fileconten.indexof ('@', offset); / function hasDecorator(fileContent, offset = 0) {const atPosition = fileconten.indexof ('@', offset); if (atPosition === -1) { return false; } if (atPosition === 1) { return true; } if (["'", '"'].includes(fileContent.substr(atPosition - 1, 1))) { return hasDecorator(fileContent, atPosition + 1); } return true; }Copy the code
Circular dependencies are not supported
Separate dependencies and resolve circular dependencies
Loading on demand is not supported
Because you are using ESbuild in the development environment, the development environment can do full import.
In antD, for example, on-demand import must be enabled in the production environment
The development environment can only take full import of style missing parts caused by on-demand import
The development environment needs to be packaged as ES5
The development environment needs to be compatible with low-end browsers, and for TSconfig, target needs to remain ES5
Es5 code packaged by TS-Loader may conflict with ES6 code packaged by ESBuild
The development environment needs to specify the configuration to set ts-Loader to ES6 code
Write the config file while keeping the development environment unchanged as far as possible
{ "extends": ".. /.. Json ", // inherit development environment configuration "compilerOptions": {"target": "es6", // override Settings "baseUrl": ".. /.. / SRC ", / / pay attention to the root directory to modify}, "include" : [".. /.. / SRC "], "exclude" : [".. /.. / node_modules ", ".. /.. / build ", ".. /.. / dist "]}Copy the code
Check the documentation for the latest TS-Loader setup available
The configFile field specifies the corresponding JSON file
If you want to make a global substitution
You can use
const TsconfigPathsPlugin = require(‘tsconfig-paths-webpack-plugin’);
Be replaced
If you want to replace the config specified in esbuild, you can go through
MinifyPlugin
To replace tsconfigRaw
Later iteration update plan
- Refactoring packaging with Vite (seriously)
- Change more loaders in development environment to ESbuild package
- Use SplitCode to separate libraries for packaging (dllpugin is not considered due to library update issues)
The optimization effect
Single compilation speed
10s-15s => 1-3s
First compilation speed
2min30s => 20s