likes
comments
collection
share

自动化构建自动化构建 1.自动化构建开始前的准备: 过程如下: 构建工具的选择(vite、webpack、turbopa

作者站长头像
站长
· 阅读数 25

自动化构建

1.自动化构建开始前的准备:

过程如下:

  • 构建工具的选择(vite、webpack、turbopack、rspack、tsup、rollup、swc

    • 确立了打包工具之后,接下来需要确立打包流程(从目前实际业务触发,例如:开发ui库使用rollup、小型项目可以使用viterspack、大型项目使用webpack、vite
  • 确定构建流程

    • 需要用到一些什么样的 loader、plugin
    • 所用到的 loader、plugin 反映出来所设计的选型(css in js、 tailwind
    • 🌈例子:
      • 如果需要文件拷贝,需要什么loader;如果需要将静态资源在打包的时候将资源上传到CDN
  • 确定构建产物输出

    • 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使用小实战

  1. 创建一个文件夹mypractise

  2. 在此文件夹下执行命令npm init -y

  3. 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"
      }
    }
    
    
  4. 新建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'],
                // },
              },
            ],
          },
        ],
      },
    };
    
    
  5. 在根目录下添加babel.config.js,内容如下:

    // 这里写了,webpack.config.js中就可以不写了
    module.exports = {
      presets:["@babel/preset-env","@babel/preset-typescript"]
    }
    
  6. 根目录下新建src文件夹,src中新建文件index.ts

    // a();
    const a = (n:number)=>{
      console.log('number是',n)
    }
    a(2);
    
  7. 最后执行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
评论
请登录