自动化构建自动化构建 1.自动化构建开始前的准备: 过程如下: 构建工具的选择(vite、webpack、turbopa
自动化构建
1.自动化构建开始前的准备:
过程如下:
-
构建工具的选择(
vite、webpack、turbopack、rspack、tsup、rollup、swc
)- 确立了打包工具之后,接下来需要确立打包流程(从目前实际业务触发,例如:开发ui库使用
rollup
、小型项目可以使用vite
和rspack
、大型项目使用webpack、vite
)
- 确立了打包工具之后,接下来需要确立打包流程(从目前实际业务触发,例如:开发ui库使用
-
确定构建流程
- 需要用到一些什么样的
loader、plugin
- 所用到的
loader、plugin
反映出来所设计的选型(css in js、 tailwind
) - 🌈例子:
- 如果需要文件拷贝,需要什么loader;如果需要将
静态资源
在打包的时候将资源上传到CDN
- 如果需要文件拷贝,需要什么loader;如果需要将
- 需要用到一些什么样的
-
确定构建产物输出
- 分
chunk
输出,按需加载(注意:处理事在内存中完成的
)
- 分
-
优化打包构建流程,
review
构建过程,优化部分阶段关于部分阶段需要优化,从以下角度入手:
-
1.如何让产物体积尽可能小?
-
按需加载(
异步组件
),减少首次加载页面的体积 -
配合缓存资源,不需要变动的包,打包合并到一起(
vendor.js
),公共资源单独打包 -
减少
commonjs
等库的使用,尽量使用ESM
的库。(因为commonjs
不能做treeshaking
) -
Externals 通过
外部导入
的形式去使用第三方资源
-
-
2.提升构建速度(时间复杂度、空间复杂度的角度去思考)
缓存cache(空间换时间)、dll
- 多线程打包-
happy-pack
- 云端构建缓存(
NX,turbrepo
)NX:blog.vincentqiao.com/nx
-
2.构建技术选型与方案:
- 初始化项目
- 依赖盘点与安装(在架构师,分析项目前期需要的库以及依赖,安装它们)
- 运行确定的
工程化脚本
- test脚本、lint脚本、type-check脚本
- 基于
git
钩子的一些处理 - 图标,图标在
iconpark
上,如果我们有图标选择器,,这个图标的来源是iconpark
,这个时候就需要在代码运行前将iconpark
上的图标同步到本地,需要定义一个脚本,当项目跑起来是,执行这个脚本。将图标当作为svg
,然后组件封装去使用。
- 打包构建
- 规范的确立(团队作业):ts、eslint、stylelint、spellcheck、gitflow 规范
3.webpack使用小实战
-
创建一个文件夹
mypractise
-
在此文件夹下执行命令
npm init -y
-
在
package.json
文件中添加要是用的包,并执行命令安装// package.json { "name": "mypreactice", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build":"webpack --config webpack.config.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": {}, "devDependencies": { "webpack": "5.89.0", "webpack-cli": "5.1.4", "babel-loader":"9.1.3", "@babel/core":"7.23.2", "@babel/preset-env":"7.23.2", "@babel/preset-typescript":"7.23.2", "typescript":"5.2.2" } }
-
新建
webpack.config.js
文件在根目录下const path = require('path'); module.exports = { mode: 'development', entry: './src/index.ts', output: { path: path.resolve(__dirname, './dist'), }, devtool: false, // 对应loader :可以选用ts-loader 或者是babel-loader(建议选用) module: { rules: [ { test: /\.ts$/, use: [ { // 自定义loader的使用 // loader:path.resolve(__dirname,"./loaders/replaceLoader.js"), // options:{ // name:"world" // } // babel-loader的使用 loader: 'babel-loader', // options: { // // presets的含义是一组plugins的集合 // presets: ['@babel/preset-env'], // }, }, ], }, ], }, };
-
在根目录下添加
babel.config.js
,内容如下:// 这里写了,webpack.config.js中就可以不写了 module.exports = { presets:["@babel/preset-env","@babel/preset-typescript"] }
-
根目录下新建src文件夹,src中新建文件
index.ts
// a(); const a = (n:number)=>{ console.log('number是',n) } a(2);
-
最后执行
pnpm run build
命令后得到dist
文件夹中的main.js
文件,内容如下// a(); var a = function a(n) { console.log('number是', n); }; a(2); /******/ })() ;
需要注意的是,这里如果将
webpack.config.js
中的loader: 'babel-loader'
注释掉,那么打包后的产物是ES6的而不是ES6,箭头函数等没有得到转换。
4.切片
还是用上面的例子,结构如下:
mypreactice ├─ dist │ └─ main.js ├─ loaders │ └─ replaceLoader.js ├─ src │ ├─ detail.ts │ ├─ home.ts │ └─ index.ts ├─ babel.config.js ├─ package.json ├─ pnpm-lock.yaml ├─ tsconfig.json └─ webpack.config.js
detail.ts
export const detail = ()=>{
console.log('detail')
}
home.ts
export const home = ()=>{
console.log('home')
}
index.ts
import { detail } from './detail';
import { home } from './home';
const a = (n:number)=>{
console.log('number是',n)
}
a(2);
detail();
home();
tsconfig.js
{
"compilerOptions": {
// 定编译目标为ES5
"target": "ES5",
},
// 指定需要编译的文件路径
"include": ["src/"]
}
webpack.config.js
const path = require('path');
const {BundleAnalyzerPlugin} = require("webpack-bundle-analyzer")
module.exports = {
// mode: 'development',
mode: 'production',
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, './dist'),
},
devtool: false,
// 对应loader :可以选用ts-loader 或者是babel-loader(建议选用)
module: {
rules: [
{
test: /\.ts$/,
use: [
{
// 自定义loader的使用
// loader:path.resolve(__dirname,"./loaders/replaceLoader.js"),
// options:{
// name:"world"
// }
// babel-loader的使用
loader: 'babel-loader',
// options: {
// // presets的含义是一组plugins的集合
// presets: ['@babel/preset-env'],
// },
},
],
},
],
},
// 分析插件
plugins:[
new BundleAnalyzerPlugin()
],
// 优化和细化 Webpack 解析模块的方式
resolve:{
// 当省略文件扩展名时,Webpack 尝试解析模块的扩展名列表
extensions:[".ts",".js"]
}
};
其他文件同上,保持不变,运行打包命令pnpm run build
后得到的产物如下:
(()=>{"use strict";console.log("number是",2),console.log("detail"),console.log("home")})();
那么如果想要detail、home单独切片呢?
修改index.ts
文件为:
import { detail } from './detail';
import { home } from './home';
const a = (n:number)=>{
console.log('number是',n)
}
const count = 6;
a(count);
if(count>1){
// 异步导入的形式
// react中使用React.lazy
// vue中使用Vue defineAsyncComponent
import ('./home').then((module)=>{
module.home()
})
}
if(count<1){
import ('./detail').then((module)=>{
module.detail()
})
}
// detail();
// home();
打包后,发现dist文件夹中是三个文件,而不是之前的一个文件了。
- react中使用React.lazy
- vue中使用Vue defineAsyncComponent
转载自:https://juejin.cn/post/7411427012128014387