美文网首页
webpack备忘手册

webpack备忘手册

作者: PandaXiong | 来源:发表于2021-02-19 17:10 被阅读0次

    什么是 webpack

       webpack 是德国开发者 Tobias Koppers 开发的模块加载器

      在 webpack 中所有的文件都将被当做模块使用。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有的这些模块打包成一个或多个 bundle。

    与 Gulp/Grunt 对比

      webpack 与 Gulp/Grunt 是没有对比性的,因为 Gulp/Grunt 是一种能够优化前端的开发流程的工具,而 webpack 是一种模块化的解决方案。不过 Webpack 的优点使得 Webpack 在很多场景下可以替代 Gulp/Grunt 类的工具。

      Grunt 和 Gulp 的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。

      webpack 的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack 将从这个文件开始找到你的项目的所有依赖文件,使用 loaders 处理它们,最后打包为一个(或多个)浏览器可识别的 JavaScript 文件。

    webpack 的安装及使用

    1. 通过 npm 全局安装 webapck
        $ npm install -g webpack
    
    1. 创建项目并初始化 package.json 文件
        $ mkdir demo1 && cd demo1
        $ npm init
    
    1. 在项目中安装 webpack
        $ npm install webpack --save-dev
    

    --save-dev 是开发时候依赖的东西,--save 是发布之后还依赖的东西

    1. 在项目中创建如下文件结构

      <pre>
      .
      ├── index.html // 显示的网页
      ├── main.js // webpack 入口
      └── bundle.js // 通过 webpack 命令生成的文件,无需创建
      </pre>

    2. 通过命令对项目中依赖的 js 文件进行打包

        # webpack 要打包的 js 文件名  打包后生成的js文件名
        $ webpack main.js bundle.js
    

      在 webpack 命令后面还可以加入以下参数

    • --watch 实时打包
    • --progress 显示打包进度
    • --display-modules 显示打包的模块
    • --display-reasons 显示模块包含在输出中的原因

      更多参数可以通过命令 webpack --help 查看

    webpack 中的四个核心概念

    • Entry 入口
    • Output 输出
    • Loaders
    • Plugins 插件

      webpack 中默认的配置文件名称是 webpack.config.js,因此我们需要在项目中创建如下文件结构:

    <pre>
    .
    ├── index.html // 显示的页面
    ├── main.js // webpack 入口
    ├── webpack.config.js // webpack 中默认的配置文件
    └── bundle.js // 通过 webpack 命令生成的文件,无需创建
    </pre>

    entry 入口

      入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后。 webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

      可以在 webpack.config.js 中 配置 entry 属性,来指定一个入口或多个起点入口,代码如下:

    moudle.exports = {
      entry: './path/file.js',
    };
    

    output 输出

       output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。你可以通过在配置指定一个 output 字段,来配置这些过程:

    const path = require('path');
    
    moudle.exports = {
      entry: './path/file.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-webpack.bundle.js',
      },
    };
    

      其中 output.path 属性用于指定生成文件的路径,output.filename 用于指定生成文件的名称。

    Loaders

       Loaderswebpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后可以利用 webpack 的打包能力,对它们进行处理。

      本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图可以直接引用模块。在更高层面上,在 webpack 的配置中 loader 有两个目标:

    1. 识别应该被对应的 loader 进行转换的那些文件(使用 test 属性)
    2. 转换这些文件,从而使其能够被添加到依赖图中(并且最终添加到 bundle 中)(use 属性)

      在开始下面的代码之前,我们需要安装 style-loadercss-loader

        $ npm install --save-dev style-loader css-loader
    

    并在项目中创建 style.css 样式文件:

    h1 {
      color: red;
    }
    

      然后在 webpack.config.js 中输入以下代码:

    const path = require('path');
    
    module.export = {
      entry: './main.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
          },
        ],
      },
    };
    

    Plugins 插件

       Loaders 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。

      想要使用一个插件,需要 require() 它,然后把它添加到 Plugins 数组中,多数插件可以通过选项自定义。也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的实例。

      在开始下面的代码之前,我们需要安装 html-webpack-plugin 插件:

        $ npm install html-webpack-plugin --save-dev
    

    它可以简化 HTML 文件的创建,为您的 webpack 包提供服务。

      然后在 webpack.config.js 中输入以下代码:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    
    const config = {
      entry: './main.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
          },
        ],
      },
      plugins: [new HtmlWebpackPlugin({ template: './index.html' })],
    };
    
    module.exports = config;
    

    运行与配置

       最后我们可以直接通过 webpack 命令编译打包,如果想要在其命令后加入参数,可以通过配置 package.json 文件中的 scripts 属性:

    {
      "scripts": {
        "build": "webpack --config webpack.config.js --progress --display-modules"
      }
    }
    

    当然如果你想要更改默认的配置文件名称,可以将 --config 后面的 webpack.config.js 配置文件名改为你自定义的名称。

      通过以下命令执行:

        $ npm run build
    

    多入口设置与 html-webpack-pugin 插件详解

      我们可以为 entry 指定多个入口。在开始代码之前,我们需要创建如下目录解构

    <pre>
    .
    ├── index.html // 显示的页面
    ├── main1.js // webpack 入口1
    ├── main1.js // webpack 入口2
    ├── style.css // 样式文件
    └── webpack.config.js // webpack 中默认的配置文件
    </pre>

      我们在 index.html 文件中输入以下内容:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>demo3</title>
      </head>
      <body></body>
    </html>
    

      我们在 main1.js 文件中输入以下内容:

        improt './style.css'
    
        var h1 = document.createElement('h1');
        h1.innertHTML = '这是 main1.js 中的内容';
        document.body.appendChild(h1);
    

      我们在 main2.js 文件中输入以下内容:

        improt './style.css'
    
        var h2 = document.createElement('h2');
        h2.innertHTML = '这是 main2.js 中的内容';
        document.body.appendChild(h2);
    

      我们在 style.css 文件中输入以下内容:

    h1 {
      color: red;
    }
    h2 {
      color: blue;
    }
    

      我们在 webpack.config.js 文件中输入以下内容:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    
    const config = {
      entry: {
        bundle1: './main1.js',
        bundle2: './main2.js',
      },
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
      },
      module: {
        rules: [{ test: /\.css$/, loader: 'style-loader!css-loader' }],
      },
      pugins: [new HtmlWebpackPlugin({ template: './index.html' })],
    };
    
    module.exports = config;
    

      完成上面的代码工作后,运行 webapck 命令,我们打开 dist 文件中的 index.html

    运行的结果并不是我们预期的那样展示 h1 的内容在前,h2 内容在后,打开生成后的 index.html 源码:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>demo3</title>
      </head>
      <body>
        <script type="text/javascript" src="bundle2.js"></script>
        <script type="text/javascript" src="bundle1.js"></script>
      </body>
    </html>
    

    从源码中便可得知,先引入的 bundle2.js 文件,也就是 main2.js 的内容,后引入的 bundle1.js 文件,也就是 main1.js 的内容。

      我们并没有在 index.html 中输入任何引入 JavaScript 文件的代码,那么使用 webpack 打包后生成的文件,是怎么引入 JavaScript 文件的呢。事实上就是通过 html-webpack-plugin 为我们生成的 index.html

    html-webpack-plugin 中的参数详解

      通过 npm 中的介绍,html-webpack-plugin 是一个 webpack 插件,可以简化 HTML 文件的创建,为我们的 webpack 包提供服务,它包含了一个改变每个编译的文件名参数。使用 lodash 模板提供我们自己的模板或者使用自己的 loader

      我们可以配置以下参数传递给 HtmlWebpackPlugin

    • title: 用于生成的 HTML 文档的标题。
    • filename: 要写入 HTML 的文件。默认为 index.html 。你也可以在这里指定一个子目录(例如:assets / admin.html)。
    • template: 引入的模板文件,具体内容可以查看文档
    • inject: true | 'head' | 'body' | false,指定引入 JavaScript 脚本文件,在生成的HTML 中的位置。默认为 true,指JavaScript 脚本文件在 <body> 元素中引入;head ,指JavaScript 脚本文件在 <head> 元素中引入,bodytrue 值相同;false 指只生成 HTML 文件,不引入任何JavaScript 脚本文件。
    • favicon: 生成的 HTML 文件中的图标路径。
    • minify: {...} | false 是否对生成的 HTML 文件压缩,默认为 false,具体配置可查看 html-minifier
    • hash: true | false ,如果为 true ,给生成的 js 文件一个独特的 hash 值,该 hash 值是该次 webpack 编译的 hash 值,这对缓存清除非常有用。默认值为 false
    • cache: true | false, 如果为 true 则只编译生成更改的内容将文件,默认值为 true
    • showErrors:true | false,如果为 true,则将错误内容添加到 HTML 中,默认值为 true
    • chunks: 指定引入的 JavaScript 脚本文件(例如:[ 'bundle1', 'bundle2' ])。
    • chunksSortMode: 'none' | 'auto' | 'dependency' |'manual' | {function} - default: 'auto',对引入的 chunks 进行排序,具体可以查看该文档
    • excludeChunks: 排除掉指定的 JavaScript 脚本文件(例如:[ 'bundle1', 'bundle2' ])。
    • xhtml: true | false,默认值是 false ,如果为 true ,则以兼容 xhtml 的模式引用文件。

      现在我们知道了 html-webpack-plugin 中的参数,下面我们就来修改 webpack.config.js 中的内容:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    
    const config = {
      entry: {
        bundle1: path.resolve(__dirname, 'main1.js'),
        bundle2: path.resolve(__dirname, 'main2.js'),
      },
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
      },
      module: {
        rules: [{ test: /\.css$/, loader: 'style-loader!css-loader' }],
      },
      plugins: [
        new HtmlWebpackPlugin({
          title: '多文件引入', // 生成 html 的标题
          filename: 'index.html', // 生成 html 文件的名称
          template: path.resolve(__dirname, 'index.html'), // 根据自己的指定的模板文件来生成特定的 html 文件
          // inject: true, // 注入选项 有四个值 ture: 默认值,script标签位于html文件的 body 底部, body: 同 true, head: script标签位于html文件的 head 底部,false:不注入script标签
          favicon: path.resolve(__dirname, 'favicon.ico'), // 生成的 html 文件设置 favicon
          minify: {
            caseSensitive: false, //是否大小写敏感
            collapseBooleanAttributes: true, //是否简写boolean格式的属性如:disabled="disabled" 简写为disabled
            collapseWhitespace: true, //是否去除空格
          },
          hash: true, // hash选项的作用是 给生成的 js 文件一个独特的 hash 值,该 hash 值是该次 webpack 编译的 hash 值。默认值为 false
          cache: true, // 默认值是 true。表示只有在内容变化时才生成一个新的文件
          showErrors: true, // showErrors 的作用是,如果 webpack 编译出现错误,webpack会将错误信息包裹在一个 pre 标签内,属性的默认值为 true
          chunks: ['bundle1', 'bundle2'], // 指定引入的 js 文件
          //excludeChunks:[ 'bundle1' ], // 排除掉某些 js 文件
          /**
           * script 标签的引用顺序
           * 'dependency' 按照不同文件的依赖关系来排序
           * 'auto' 默认值,插件的内置的排序方式
           * 'none'
           * 'manual'
           * funciton 自定义排序,与JS中自定义数组的sort回调一个含义, 具体可以看 https://github.com/jantimon/html-webpack-plugin/issues/481
           */
          chunksSortMode: function(chunk1, chunk2) {
            var orders = ['bundle1', 'bundle2'];
            var order1 = orders.indexOf(chunk1.names[0]);
            var order2 = orders.indexOf(chunk2.names[0]);
            return order1 - order2;
          },
          xhtml: false, // 一个布尔值,默认值是 false ,如果为 true ,则以兼容 xhtml 的模式引用文件
        }),
      ],
    };
    
    module.exports = config;
    

      完成上面的代码工作后,运行 webapck 命令,我们打开 dist 文件中的 index.html。

      Nice!与我们的预期效果显示一致。在对 html-webpack-plugin 的介绍中,提到了 lodash 模板, 那么该怎么用呢?我们再次修改 webpack.config.js 中的内容,为 HtmlWebpackPlugin 传入 Date 参数:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    
    const config = {
      entry: {
        bundle1: path.resolve(__dirname, 'main1.js'),
        bundle2: path.resolve(__dirname, 'main2.js'),
      },
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
      },
      module: {
        rules: [{ test: /\.css$/, loader: 'style-loader!css-loader' }],
      },
      plugins: [
        new HtmlWebpackPlugin({
          date: new Date(),
          title: '多文件引入', // 生成 html 的标题
          filename: 'index.html', // 生成 html 文件的名称
          template: path.resolve(__dirname, 'index.html'), // 根据自己的指定的模板文件来生成特定的 html 文件
          // inject: true, // 注入选项 有四个值 ture: 默认值,script标签位于html文件的 body 底部, body: 同 true, head: script标签位于html文件的 head 底部,false:不注入script标签
          favicon: path.resolve(__dirname, 'favicon.ico'), // 生成的 html 文件设置 favicon
          minify: {
            caseSensitive: false, //是否大小写敏感
            collapseBooleanAttributes: true, //是否简写boolean格式的属性如:disabled="disabled" 简写为disabled
            collapseWhitespace: true, //是否去除空格
          },
          hash: true, // hash选项的作用是 给生成的 js 文件一个独特的 hash 值,该 hash 值是该次 webpack 编译的 hash 值。默认值为 false
          cache: true, // 默认值是 true。表示只有在内容变化时才生成一个新的文件
          showErrors: true, // showErrors 的作用是,如果 webpack 编译出现错误,webpack会将错误信息包裹在一个 pre 标签内,属性的默认值为 true
          chunks: ['bundle1', 'bundle2'], // 指定引入的 js 文件
          //excludeChunks:[ 'bundle1' ], // 排除掉某些 js 文件
          /**
           * script 标签的引用顺序
           * 'dependency' 按照不同文件的依赖关系来排序
           * 'auto' 默认值,插件的内置的排序方式
           * 'none'
           * 'manual'
           * funciton 自定义排序,与JS中自定义数组的sort回调一个含义, 具体可以看 https://github.com/jantimon/html-webpack-plugin/issues/481
           */
          chunksSortMode: function(chunk1, chunk2) {
            var orders = ['bundle1', 'bundle2'];
            var order1 = orders.indexOf(chunk1.names[0]);
            var order2 = orders.indexOf(chunk2.names[0]);
            return order1 - order2;
          },
          xhtml: false, // 一个布尔值,默认值是 false ,如果为 true ,则以兼容 xhtml 的模式引用文件
        }),
      ],
    };
    
    module.exports = config;
    

    更改 index.html 中的内容,lodash 模板默认支持的是 ejs 模板的语法:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>demo3</title>
      </head>
      <body>
        <%= htmlWebpackPlugin.options.date %>
      </body>
    </html>
    

      完成上面的代码工作后,运行 webapck 命令,我们打开 dist 文件中的 index.html。

      通过运行结果,我们可以发现在顶部输出了当前时间,也就是 HtmlWebpackPlugin 传入的参数,实际上 HtmlWebpackPlugin 中的参数都可以通过 htmlWebpackPlugin.options.参数名称 输出,我就不一一列举。

    Babel

      Babel 是一个工具链,主要用于在旧的浏览器或环境中将 ECMAScript 2015+ 代码转换为向后兼容版本的 JavaScript 代码。

    安装依赖包

    npm i -D babel-loader @babel/core @babel/preset-env
    
    • babel-loader:用于 babel 在 webapck 中的加载模块。
    • @babel/core:babel 编译工具;
    • @babel/preset-env:babel 生成指定支持浏览器版本的编译工具。

    babel 支持两种配置,一种是在项目根目录下创建 .babelrc 配置文件,另一种是通过 webpack loader options 的方式配置

    • .babelrc
    {
      "presets": [
        [
          "@babel/preset-env",
          {
            // 用于指定浏览器版本号
            "targets": {
              "browsers": "last 2 version"
            }
          }
        ]
      ]
    }
    
    • webpack loader options 配置
    {
      "module": {
        "rules": [
          {
            "test": /\.js$/,
            "exclude": /(node_modules)/,
            "loader": "babel-loader",
            "options": {
              "presets": [
                [
                  "@babel/preset-env",
                  {
                    // 用于指定浏览器版本号
                    "targets": {
                      "browsers": "last 2 version"
                    }
                  }
                ]
              ]
            }
          }
        ]
      }
    }
    

    Babel 默认只转换语法,而不转换新的 API,如 Set、Promise、Map 等或是 ES6 对 Array、String 等扩展,如果需要使用新的 API 还需要使用对相应的 转换插件 或 polyfill

    • Babel Polyfill
    npm i --save @babel/polyfill
    

    只需在入口头部引入即可

    import '@babel/polyfill';
    // 或
    require('@babel/polyfill');
    

    上面的使用方法,会导致打包后的文件过大,由于是在入口文件直接引入 polyfill,从而将会导入 polyfill 整个包,增加了无用代码。

    @babel/preset-envuseBuiltIns: 'usage' 按需引入,就是用于解决上面的问题。

    {
      "presets": [
        [
          "@babel/preset-env",
          {
            // 用于指定浏览器版本号
            "targets": {
              "browsers": "last 2 version"
            },
            "useBuiltIns": "usage"
          }
        ]
      ]
    }
    

    @babel/polyfill 是通过改写全局 prototype 的方式对新的 API 支持,比较适合单独运行的项目。

    • Babel RunTime Transform
    npm i @babel/runtime --save
    npm i @babel/plugin-transform-runtime --save-dev
    
    {
      "presets": [
        [
          "@babel/preset-env",
          {
            // 用于指定浏览器版本号
            "targets": {
              "browsers": "last 2 version"
            }
          }
        ]
      ],
      "plugins": ["@babel/plugin-transform-runtime"]
    }
    

    @babel/runtime 的 polyfill 对象是临时构造并 import/require 的,因此并不是真正的全局引用,由于不是全局引用,对于实例化对象的方法,并不能生效。比较适合编写 第三方类库。

    文件操作

    file-loader 可以解析项目中的 url 引入(不禁限于 CSS),根据配置,将图片拷贝到相应路径,并修改打包后文件的引用路径。

    {
      "test": /\.(png|jpe?g|gif)$/,
      "loader": "file-loader",
      "options": {
        // 输出文件名称,默认为:'[hash].[ext]'
        "name": "[name].[hash:8].[ext]",
        // 指定输出文件存放路径,默认为当前目录
        "outputPath": "assets/images",
        // 指定输出文件 公共路径
        // publicPath: '../',
        // 如果是 true,生成一个文件(向文件系统写入一个文件)。 如果是 false,loader 会返回 public UR不会生成文件
        "emitFile": true
      }
    }
    

    url-loaderfile-loader 的作用是一样的,但是 url-loader 可以通过 limit 配置限制输出大小,如果小于 limit 字节的文件会被转成 Base64 编码,大于则会拷贝文件。

    {
      "test": /\.(png|jpe?g|gif)$/,
      "loader": "url-loader",
      "options": {
        // 限制输出文件大小,如果输出文件小于该限制,则被转成 base64 编码,大于则会拷贝文件
        "limit": 1024,
        // 输出文件名称,默认为:'[hash].[ext]'
        "name": "[name].[hash:8].[ext]",
        // 指定输出文件存放路径,默认为当前目录
        "outputPath": "assets/images"
        // 指定输出文件 公共路径
        // publicPath: '../',
      }
    }
    

    img-loader 可以压缩图片,也可以使用 image-webpack-loader 代替。

    npm i -D img-loader imagemin imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo
    

    插件具体参数可以查看 github

    {
      "loader": "img-loader",
      "options": {
        "plugins": [
          require("imagemin-gifsicle")({}),
          require("imagemin-mozjpeg")({}),
          require("imagemin-pngquant")({}),
          require("imagemin-svgo")({})
        ]
      }
    }
    

    html-loader 可以设置 html 中的某些片段是要交给 webpack 处理的。

    {
      "test": /\.html$/,
      "loader": "html-loader",
      "options": {
        // 设置交由 webpack 处理的属性
        "attrs": ["img:src", "img:data-src"]
      }
    }
    

    当我们在使用第三方库时,如果每个模块都用到了它,但我们并不想在每个模块中重复去写 importrequire
    ,我们可以使用下面两种方式:

    • webpack.ProvidePlugin
    {
      "resolve": {
        "alias": {
          // 定义别名 指定本地文件路径,$ 表示将 jquery 关键字解析到某个目录的文件下,而不是解析某个目录
          "jquery$": path.join(__dirname, "./lib/jquery.min.js")
        }
      },
      "plugins": [
        new webpack.ProvidePlugin({
          // "$": "jquery", // 导入 npm 依赖包
          // "$": ["./lib/jquery.min.js"] // 指定本地文件路径
          "$": "jquery"
        })
      ]
    }
    
    • imports-loader
    npm i imports-loader
    
    {
      "test": /\.js$/,
      "loader": "imports-loader",
      "options": {
        "$": "jquery"
      }
    }
    

    CSS

    mini-css-extract-plugin 能够将 CSS 提取到单独的文件中,它为每个包含 CSS 的 JS 文件创建了一个 CSS 文件。

    npm install --save-dev mini-css-extract-plugin
    
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
    {
      "module": {
        "rules": {
          "test": /\.css$/,
          "use": [
            // mini-css-extract-plugin 只能用于生产环境,因此在 loader 中需要加入一个判断
            process.env.NODE_ENV === "development"
              ? "style-loader"
              : {
                  "loader": MiniCssExtractPlugin.loader,
                  "options": {
                    // CSS 样式用的背景图片 会与抽取后的 CSS 文件路径有冲突,在此设置公共相对路径
                    "publicPath": "../../"
                  }
                }
          ]
        }
      },
      "plugins": [
        new MiniCssExtractPlugin({
          // 用于设置提取的 CSS 文件名称与存储路径
          "filename": "assets/styles/[name].[hash:8].css",
          // 用于设置异步加载 CSS 文件名称与存储路径,例如: import('./assets/styles/test.js')
          "chunkFilename": "assets/styles/[id].[chunkhash:8].css"
        })
      ]
    }
    

    optimize-css-assets-webpack-plugin 能够压缩 CSS 文件大小。

    npm install --save-dev optimize-css-assets-webpack-plugin
    
    const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
    
    {
      "plugins": [
        new OptimizeCssAssetsPlugin({
          // 匹配需要压缩的 CSS 文件正则,默认为 /\.css$/g
          // assetNameRegExp: /\.optimize\.css$/g,
          // 设置 CSS 压缩工具 默认使用的是  cssnano
          // cssProcessor: require('cssnano'),
          // 设置 CSS 压缩工具的 options ,默认 {}
          // cssProcessorOptions: {},
          // 设置 CSS 压缩工具插件的 options, 默认 {}
          // cssProcessorPluginOptions: {},
          // 插件输出信息是否输出在控制台,默认 true
          // canPrint: true,
        })
      ]
    }
    

    PostCSS 是一个允许使用 JS 插件转换样式的工具。

    npm install postcss postcss-loader --save-dev
    
    • autoprefixer 添加了 vendor 浏览器前缀,它使用 Can I Use 上面的数据。
    npm install autoprefixer --save-dev
    
    {
      "module": {
        "rules": [
          {
            "test": /\.css$/,
            "use": [
              "style-loader",
              "css-loader",
              {
                "loader": "postcss-loader",
                "options": {
                  "ident": "postcss",
                  plugins:[
                    require('autoprefixer')({
                      // 设置兼容浏览器版本
                      "browsers": ['last 2 versions'],
                    })
                  ]
                  "sourceMap": true
                }
              }
            ]
          }
        ]
      }
    }
    

    不难发现 autoprefixer 中需要配置 browsers,Babel 中也需要配置,我们可以通过下面两种方法配置:

    • package.json
      "browserslist": [
        "last 2 version"
      ]
    
    • .browserslistrc
    last 2 version
    
    • postcss-preset-env 能够转换还未兼容 CSS 例如 --color 变量

    postcss-preset-env 中已经引入了 autoprefixer,因此使用它的时候可以不用引入 autoprefixer。

    npm install postcss-preset-env --save-dev
    
    {
      "module": {
        "rules": [
          {
            "test": /\.css$/,
            "use": [
              "style-loader",
              "css-loader",
              {
                "loader": "postcss-loader",
                "options": {
                  "ident": "postcss",
                  plugins:[
                    require('postcss-preset-env')
                  ]
                  "sourceMap": true
                }
              }
            ]
          }
        ]
      }
    }
    

    Webpack 打包优化

    • 提取公共代码:减少代码冗余,提高用户下载代码带宽。

    Webpack 4 提供了内置插件 webpack.SplitChunksPlugin

    {
      "optimization": {
        "splitChunks": {
          /**
           * 拆分块的名称:boolean: true | function (module, chunks, cacheGroupKey) | string
           * 如果为 true 将自动生成基于块和缓存组密钥的名称,生产环境下建议 false 避免更改名称
           * 如果是一个函数允许自定义名称,不推荐,容易造成代码下载冗余
           */
          "name": false,
          "automaticNameDelimiter": "~", // 用于指定生成名称的分隔符
          "chunks": "initial", // 用于指定那些模块需要分割, 可选项 "initial"(初始化) | "all"(默认) | "async"(动态加载)
          "maxAsyncRequests": 1, // 按需加载时的最大并行请求数。
          "maxInitialRequests": 1, // 入口点处的最大并行请求数。
          "minChunks": 1, // 分割前必须共享模块的最小块数。
          // 缓存组会继承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用于配置缓存组。
          "cacheGroups": {
            // 自定义缓存组属性
            "vendors": {
              "test": /[\\/]node_modules[\\/]/, // 控制此缓存组选择的模块,使用正则表达式匹配
              "filename": "venders", // 拆分出块的名称
              "reuseExistingChunk": true, // 可设置是否重用已用chunk 不再创建新的chunk
              "priority": "0" // 优先级高的chunk为被优先选择,优先级一样的话,size大的优先被选择
              // enforce: true, // 忽略外部 maxAsyncRequests、maxInitialRequests、minSize、minChunks 始终以 缓存组配置执行
            }
          }
        }
      }
    }
    
    • 代码分割与懒加载:能够在最短的时间内,展示页面。通过动态加载模块的方式实现。

      • webpack 内置 methods

        /**
         * 动态引入 模块
         * dependencies: [] 需要加载的模块,并不会执行,需要在回调函数中 require
         * callback: 回调函数,执行动态加载模块的方法
         * errorCallback: 错误回调,可以省略
         * chunkName: 拆分块名称
         */
        require.ensure(dependencies, callback, errorCallback, chunkName)
        
        // 只接收引入的模块 而不执行,当两个子模块同时依赖一个模块,可以通过这种引用将公共模块提前引入到父模块中
        require.include(dependencies)
        
      • ES2015 Loader 规范

        import(/* webpackChunkName: 生成的 chunk 名称 */).then() // 此时引入的 模块已经执行
        

    相关文章

      网友评论

          本文标题:webpack备忘手册

          本文链接:https://www.haomeiwen.com/subject/mtwaxltx.html