自动清理构建目录产物

  • 每次构建的时候不会清理目录,造成构建的输出目录output文件越来越多
  • 在启动命令追加 rm -rf ./dist/ && weback (*不建议使用)

    clean-webpack-plugin

  • 默认删除output指定的目录

    1. npm i clean-webpack-plugin@2.0.2 -D

    webpack配置 ```javascript const CleanWebPackPlugin = require(“clean-webpack-plugin”)

plugins: [ new CleanWebPackPlugin() ]

  1. <a name="PRWyp"></a>
  2. ### 自动补齐CSS3前缀
  3. - CSS3 属性兼容各大浏览器内核
  4. - 使用 postcss-loader 和 autoprefixer
  5. ```javascript
  6. npm i postcss-loader@3.0.0 autoprefixer@9.5.1 -D

webpack配置

{
  test: /.less$/,
    use: [
      MiniCssExtractPlugin.loader,
      'css-loader',
      'less-loader',
      {
        loader: "postcss-loader",
        options: {
          // "ident": "postcss",
          "plugins": () => [
            //postcss 需要的插件
            require('autoprefixer')({
              browsers: ['last 1 version', '>1%', 'ios 7']
            })
          ]
        }
      }
    ]
}

移动端CSS px 转 rem 适配

  • w3c 出现了 rem 自动适配不同分辨率的移动端设备
  • 使用px2rem-loader 将 px 转换为 rem
  • lib-flexible: 动态计算 rem 根元素的单位

    npm i px2rem-loader@0.1.9 -D
    npm i lib-flexible@0.3.2 -S
    

    webpack 配置

    {
          test: /.less$/,
          use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            'less-loader',
            {
              loader: "postcss-loader",
              options: {
                // "ident": "postcss",
                "plugins": () => [
                  //postcss 需要的插件
                  require('autoprefixer')({
                    browsers: ['last 1 version', '>1%', 'ios 7']
                  })
                ]
              }
            },
            {
              loader: "px2rem-loader",
              options: {
                remUnit: 75, //1个rem 代表 75px
                remPrecision: 8 //px转rem 时小数点后8位
              }
            }
          ]
        },
    
  • 在 未打包的html 顶部引入 lib-flexible: 动态计算 rem 根元素的单位

    资源内联

    资源内联的意义

  • 代码层面

    • 将页面框架的初始化脚本打包压缩到输出的构建产物
    • 上报相关的打点
    • css内联 避免页面闪动,页面优化,减少白屏时间
  • 请求层: 减少HTTP网络请求数
    • 小图片或者字体内联(url-loader中参数 limit :小于 limit 则内联到文件中)
  • 减少白屏渲染时间

    HTML | JS 内联

  • raw-loader 内联html或者js

    npm i raw-loader@0.5.1 -D
    
    //内联 html
    <script${ require('raw-loader!babel-loader./xxx.html')}></script>
    //内联 js
    <script${ require('raw-loader!babel-loader../../node_modules/lib-flexible/flexible.js')}></script>
    

    CSS 内联

  • 借助 style-loader

    {
    loader: 'style-loader',
    options: {
      insertAt: 'top', //样式插入到<head>
      singleton: true, //将所有 style 标签合成一个
    }
    }
    
  • 借助 html-inline-css-webpack-plugin (一般用这个)

    多页面应用打包

    打包思路

  • 每个页面对应一个entry, 一个 html-webpack-plugin

  • 缺点:每次新增或删除页面需要改 webpack 配置

    打包方案

  • 动态获取 entry 和 设置 html-webpack-plugin 数量

  • 利用 glob.sync, 动态获取 入口文件 ```javascript entry: glob.sync(path.join(__dirname, ‘./src/*/index.js’))

entry: { index: ‘./src/index/index.js’, search: ‘./src/search/index.js’ }

const setMPA = () => { const entry = {} const htmlWebPackPlugIn = [] const entryFiles = glob.sync(path.join(dirname, ‘./src//index.js’)) entryFiles.forEach((index) => { const match = index.match(/src\/(.)\/index.js/) const pageName = match && match[1] entry[pageName] = index htmlWebPackPlugIn.push( new HtmlWebPackPlugIn({ template: path.join(dirname, src/${pageName}/index.html), filename: ${pageName}.html, chunks: [pageName], // 将打包生成的所有资源(JS/CSS)自动引入到html inject: true, minify: { // 移除空格 collapseWhitespace: true, // 移除注释 removeComments: true, } }) ) }) return { entry, htmlWebPackPlugIn } }

```javascript
npm i glob@7.1.4 -D

source-map

  • 在项目开发中通过sourcemap定位到源码位置去调试
  • 开发环境开启,线上环境关闭

    • 线上排查问题的时候可以将 sourcemap 上传到错误监控系统
      devtool: 'cheap-module-source-map'
      

      关键字

  • eval: 使用 eval 包裹模块代码

  • source map: 产生.map 文件
  • cheap: 不包含列信息
  • inline: 将.map文件作为 DataURL 嵌入,不单独生成.map 文件
  • module:包含loader 的sourcemap

    提取页面公共资源

    基础库分离

  • 将 react,react-dom 基础包通过 cdn 引入,不打入 bundle 中(推荐使用

    • 虽然可以使用 splitChunksPlugin 进行分离,但是构建后文件还存在该库,影响 资源的 请求下载
  • 使用 html-webpack-externals-plugin
    npm i html-webpack-externals-plugin@3.8.0 -D
    
    ```sql const HtmlWebpackExternalsPlugin = require(‘html-webpack-externals-plugin’);

module.exports = { // 其它省略… plugins: [ new HtmlWebpackExternalsPlugin({ externals: [ { module: ‘react’, entry: ‘https://now8.gtimg.com/now/lib/16.2.0/react.min.js‘, global: ‘React’ }, { module: ‘react-dom’, entry: ‘https://now8.gtimg.com/now/lib/16.2.0/react-dom.min.js‘, global: ‘ReactDom’ } ] }) ], // 其它省略… }

然后在对应的html文件中引入react react-dom
```html
<!-- html-webpack-externals-plugin将 react,react-dom分离,基础包通过 cdn 引入 -->
<script type="text/javascript" src="https://now8.gtimg.com/now/lib/16.2.0/react.min.js"></script>
<script type="text/javascript" src="https://now8.gtimg.com/now/lib/16.2.0/react-dom.min.js"></script>
  • 使用 splitChunks 分离
    • 记得在 HtmlWebPackPlugIn 中添加 打包生成的 chunks vendor ```javascript optimization: { splitChunks: { cacheGroups: { // 缓存组会继承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用于配置缓存组。 vendor: { // key 为entry中定义的 入口名称
       chunks: "all",        // 必须三选一: "initial"(初始化) | "all" | "async"(默认就是异步)
       test: /(react|react-dom)/,     // 正则规则验证,如果符合就提取 chunk
       name: "vendor",           // 要缓存的 分隔出来的 chunk 名称
       // minSize: 0,
       // minChunks: 1,
      
      } } } }

new HtmlWebPackPlugIn({ template: path.join(__dirname, src/${pageName}/index.html), filename: ${pageName}.html, chunks: [‘vendor’, pageName], // 将打包生成的所有资源(JS/CSS)自动引入到html inject: true, minify: { // 移除空格 collapseWhitespace: true, // 移除注释 removeComments: true, } })


<a name="t3xLy"></a>
#### 公共脚本分离
[参考](https://www.cnblogs.com/sunshq/p/11051675.html)

- 利用 splitChunksPlugin 进行公共脚本分离
- **chunks 参数说明**
   - **async 异步引入的库进行分离(默认)**
   - **initial 同步引入的库分离**
   - **all 所有引入的库分离 (推荐使用)**
```sql
optimization: {
    splitChunks: { 
      chunks: "initial",         // 代码块类型 必须三选一: "initial"(初始化) | "all"(默认就是all) | "async"(动态加载) 
      minSize: 0,                // 最小尺寸,默认0
      minChunks: 1,              // 最小 chunk ,默认1
      maxAsyncRequests: 1,       // 最大异步请求数, 默认1
      maxInitialRequests: 1,     // 最大初始化请求书,默认1
      name: () => {},            // 名称,此选项课接收 function
      cacheGroups: {                // 缓存组会继承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用于配置缓存组。
        priority: "0",              // 缓存组优先级,即权重 false | object |
        vendor: {                   // key 为entry中定义的 入口名称
          chunks: "initial",        // 必须三选一: "initial"(初始化) | "all" | "async"(默认就是异步)
          test: /react|lodash/,     // 正则规则验证,如果符合就提取 chunk
          name: "vendor",           // 要缓存的 分隔出来的 chunk 名称
          minSize: 0,
          minChunks: 1,
          enforce: true,
          reuseExistingChunk: true   // 可设置是否重用已用chunk 不再创建新的chunk
        }
      }
    }
  }