0
点赞
收藏
分享

微信扫一扫

webpack 之 webpack 进阶用法的提取页面公共资源、treeShaking、scopeHoisting、代码分割、webpack 与 ESLint 结合和webpack 打包组件与基础库

一、 webpack 进阶用法的提取页面公共资源、treeShaking、scopeHoisting、代码分割、webpack与 ESLint 结合和webpack 打包组件与基础库

  1. 基础库分离,思路是将 react、react-dom 基础包通过 cdn 引入,不打入 bundle 中,方法是使用 html-webpack-externals-plugin
  2. 利用 SplitChunksPlugin 进行公共脚本分离,Webpack4 内置的,替代 CommonsChunkPlugin 插件。chunks 参数说明,async 异步引入的库进行分离(默认),initial 同步引入的库进行分离,all 所有引入的库进行分离(推荐),代码如下:
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests:3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        }
      }
    }
  }
};
  1. 利用 SplitChunksPlugin 分离基础包,test 是匹配出需要分离的包,代码如下:
module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        commons: {
          test: /(react|react-dom)/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};
  1. 利用 SplitChunksPlugin 分离页面公共文件,minChunks 设置最小引用次数为 2 次,minSize 分离的包体积的大小,代码如下:
module.exports = {
  optimization: {
    splitChunks: {
      minSize: 0,
      cacheGroups: {
        commons: {
          name: 'commons',
          chunks: 'all',
          minChunks: 2
        }
      }
    }
  }
};
  1. tree shaking 摇树优化,1 个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到 bundle 里面去,tree shaking 就是只把用到的方法打入 bundle,没用到的方法会在 uglify 阶段被擦除掉。对于使用,webpack 默认支持,在 .babelrc 里设置 modules: false 即可,production mode 的情况下默认开启。对于要求,必须是 ES6 的语法,CJS 的方式不支持。
  2. DCE,如下所示:
  • 代码不会被执行,不可到达
  • 代码执行的结果不会被用到
  • 代码只会影响死变量,只写不读
  1. Tree shaking 原理,如下所示:
  • 利用 ES6 模块的特点,只能作为模块顶层的语句出现,important 的模块名只能是字符串变量,important bindingimmutable
  • 代码擦除,uglify 阶段删除无用代码
  1. 对于现象,构建后的代码存在大量闭包代码,以此导致的问题,如下所示:
  • 大量函数闭包包裹代码,导致代码体积增大,模块越多越明显
  • 运行代码时创建的函数作用域变多,内存开销变大
  1. 对于 webpack 模块转换分析,被 webpack 转换后的模块会带上一层包裹,important 会被转换成 _webpack_requirewebpack 的模块机制,如下所示:
  • 打包出来的是一个 IFE 匿名闭包
  • modules 是一个数组,每一项是一个模块初始化函数
  • _webpack_require 用来加载模块,返回 module.exports
  • 通过 WEBPACK_REQUIRE_METHOD(0) 启动程序
  1. scope hoisting 原理,将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突。通过对比,使用 scope hoisting 可以减少函数声明代码和内存开销。
  2. scope hoisting 使用,webpack modeproduction 默认开启,必须是 ES6 语法,CJS 不支持,代码如下:
module.exports = {
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name][chunkhash:8].js',
    path: _dirname + '/dist'
  },
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
};
  1. 代码分割的意义,对于大的 Web 应用来讲,将所有的代码都放在一个文件中显然是不够有效的,特别是当你的某些代码块是在某些特殊的时候才会被使用到。webpack 有一个功能就是将你的代码库分割成 chunks 语块,当代码运行到需要它们的时候再进行加载,使用的场景,如下所示:
  • 抽离相同代码到一个共享块
  • 脚本懒加载,使得初始下载的代码更小
  1. 懒加载 JS 脚本的方式,如下所示:
  • CommonJSrequire.ensure
  • ES6:动态 import,目前还没有原生支持,需要 babel 转换
  1. 如何使用动态 import,如下所示:
  • 安装 babel 插件,通过 npm install @babel/plugin-syntax-dynamic-important --save-dev 命令
  • ES6 动态 import,目前还没有原生支持,需要 babel 转换,{ "plugins": ["@babel/plugin-syntax-dynamic-important"], }
  1. 制定团队的 ESLint 规范,如下所示:
  • 不重复造轮子,基于 eslint:recommend 配置并改进
  • 能够帮助发现代码错误的规则,全部开启
  • 帮助保持团队的代码风格统一,而不是限制开发体验
  1. ESLint 如何执行落地,如下所示:
  • CI/CD 系统集成
  • webpack 集成
  1. 对于方案一,webpackCI/CD 集成,如下所示:
  • 增加 lint pipline
  • 本地开发阶段增加 precommit 钩子,安装 husky,通过 npm install husky --save-dev 命令
  • 增加 npm script,通过 lint-staged 增量检查修改的文件,代码如下:
"scripts": {
  "precommit": "lint-staged"
},
"lint-staged": {
   "linters": {
      "*.{js,scss}": ["eslint --fix", "git add"]
   }
},
  1. 对于方案二,webpackESLint 集成,使用 eslint-loader,构建时检查 JS 规范,如下所示:
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          "babel-loader",
          "eslint-loader"
        ]
      }
    ]
  }
};
  1. webpack 打包库和组件,webpack 除了可以用来打包应用,也可以用来打包 js 库,实现一个大整数加法库的打包,如下所示:
  • 需要打包压缩版和非压缩版本
  • 支持 ADM/CJS/ESM 模块引入
  1. 库的目录结构和打包要求,打包输出的库名称,未压缩版 large-number.js,压缩版 large-number.min.js。对于支持的使用方式,支持 ES module、支持 CJS 和支持 AMD。如何将库暴露出去,library 指定库的全局变量,libraryTarget 支持库引入的方式,代码如下:
module.exports = {
  mode: "production",
  entry: {
    "large-number": "./src/index.js",
    "large-number.min": "./src/index.js"
  },
  output: {
    filename: "[name].js",
    library: "largeNumber",
    libraryExport: "default",
    libraryTarget: "umd"
  }
};
  1. 如何只对 .min 压缩,通过 include 设置只压缩 min.js 结尾的文件,代码如下:
module.exports = {
  mode: "none",
  entry: {
    "large-number": "./src/index.js",
    "large-number.min": "./src/index.js"
  },
  output: {
    filename: "[name].js",
    library: "largeNumber",
    libraryTarget: "umd"
  },
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        include: /\.min\.js$/,
      })
    ]
  }
};
  1. 对于设置入口文件,package.jsonmain 字段为 index.js,代码如下:
if (process.env.NODE_ENV === 'production') {
  module.exports = require("./dist/large-number.min.js");
} else {
  module.exports = require("./dist/large-number.js");
}
举报

相关推荐

0 条评论