文档

这里介绍webpack的一些高级配置,包括根据不同环境(开发和生产)使用不同的配置文件;引入 SCSS, LESS和 Stylus,以及引入图片和懒加载等。

详见 webpack 的 英文文档中文文档

插件与加载器

webpack使用和拓展通过两种方式来实现:加载插件或安装加载器。

两者的区别

  • 首先本意上的差别。
  • 加载器主要用来加载一个资源文件,插件用来加强、扩展功能。
  • 当然 loader 也变相地扩展了 webpack ,但是它只专注于转化文件。
  • plugin 的功能更加丰富,不仅局限与资源的加载。
  • loader 必定是一个文件加载为另外一个文件,而 plugin 可能是综合多个文件合并为一个文件。

引入

引入SCSS

引入 .scss 文件。

要求

请使用 dart-sass 代替 node-sass,因为后者已经过时了而且很难安装。

安装

1
$ yarn add sass-loader dart-sass --dev

下面示意 sass-loader 和 css-loader 、 style-loader 的链式调用。

引入到js

index.js

1
import './style-one.scss'

style-one.scss

1
2
3
4
5
$color: red;

body{
  color: $color;
}

配置

sass-loader 默认使用 node-sass ,你需要把它修改为 dart-sass。

webpack.config.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
    ...
    module: {
       rules: [
+        {
+           test: /\.scss$/,
+           use: [
+               "style-loader", // 将 JS 字符串生成为 style 节点
+               "css-loader", // 将 CSS 转化成 CommonJS 模块
+?              //"sass-loader"  将 Sass 编译成 CSS,如果只写这一行,默认使用 Node Sass
+               {
+                 loader: "sass-loader",
+                 options: {
+                   implementation: require('dart-sass')
+                 }
+               },
+           ]
+       }
      ]
    }
}

引入LESS

引入 .less 文件。

要求

此模块需要 Node v6.9.0+ 和 webpack v4.0.0+。

安装

1
$ yarn add less-loader less --dev

下面示意 less-loader 和 css-loader 、 style-loader 的链式调用。

引入到js

index.js

1
import './style-two.less'

style-two.less

1
2
3
4
5
@color: red;

body{
  color: @color;
}

配置

webpack.config.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
module.exports = {
    ...
    module: {
        rules: [
+         {
+           test: /\.less$/,
+           use: [
+               "style-loader", // 将 JS 字符串生成为 style 节点
+               "css-loader", // 将 CSS 转化成 CommonJS 模块
+               "less-loader", // 将 Less 编译成 CSS
+           ]
+         },
        ]
    }
}

引入Stylus

引入 .styl 文件。

安装

1
$ yarn add stylus-loader stylus --dev

下面示意 less-loader 和 css-loader 、 style-loader 的链式调用。

引入到js

index.js

1
import './style-three.styl'

style-three.styl

1
2
3
4
5
setColor = red;

body{
  color: setColor;
}

配置

webpack.config.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
module.exports = {
    ...
    module: {
        rules: [
+         {
+           test: /\.less$/,
+           use: [
+               "style-loader", // 将 JS 字符串生成为 style 节点
+               "css-loader", // 将 CSS 转化成 CommonJS 模块
+               "stylus-loader", // 将 Stylus 编译成 CSS
+           ]
+         }
        ]
    }
}

使用file-loader

file-loader 加载器可以根据 require 路径来把文件变成文件路径,以达到加载目的。

安装

1
$ yarn add file-loader --dev

引入图片

首先将图片 logo.png 放入 src 目录的 assets 文件夹中(可以放在src根目录下,根据你的 require 路径)

js中引入

./assets/index.html

1
2
3
<body>
  <div id="logo"></div>
</body>

index.js

1
2
3
4
5
6
import png from './one.png'

const logo = document.getElementById('logo')
logo.innerHTML = `
  <img src="${png}">
`

配置

webpack.config.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
module.exports = {
  module: {
    rules: [
+     {
+       test: /\.(png|svg|jpg|gif)$/,
+       use: [
+         {
+           loader: 'file-loader',
+           options: {
+             context: 'project',
+             publicPath: 'assets',
+           },
+         },
+       ],
+     },
    ],
  },
}

懒加载

懒加载或者按需加载,是一种很好的优化网页或应用的方式。

这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。

这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。

实现思路

import( ) 将其当成一个函数去加载文件,得到一个 promise ,然后在 .then 设置成功后调用得到的结果(可以得到一个函数),或失败后报错等。

示例

创建需要懒加载的文件。

1
$ touch src/lazy.js

./assets/index.html

1
2
3
<body>
  <div id="lazy-load"></div>
</body>

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const div = document.getElementById('lazy-load')
const button = document.createElement('button')

button.innerText = 'I am Lazy-Load'

button.onclick = () => {
  const promise = import('./lazy')
  promise.then((module)=>{
    module.default()
  },()=>{
    console.log('Error')
  })
}

div.appendChild(button)

lazy.js

1
2
3
4
export default function lazyModule() {
  console.log('This is a lazy loading module.')
  alert('This is a lazy loading module.')
}

使用不同的配置文件

在开发模式和生产模式,选择不同的配置,达到使用 webpack 的最优化选择。

在开始之前,你需要先配置 json 文件中的 script 脚本。让不同方法使用不同的配置文件。

package.json

1
2
3
4
5
6
{
   "script": {
+    "start": "webpack-dev-server --config webpack.config.dev.js",
+    "build": "rm -rf dist ; webpack --config webpack.config.prod.js"
   }
}

配置base文件

两种模式共有的配置。

你要在下面两种模式的配置文件中继承该配置。同时删除默认的配置文件。

webpack.config.base.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const HtmlWebpackPlugin = require("html-webpack-plugin")
const path = require("path")

module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "index.[contenthash].js"
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "Use webpack to load HTML",
      template: "src/assets/index.html"
    })
  ],
  module: {
    rules: [
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: ["file-loader"]
      },
      {
        test: /\.styl$/,
        loader: ["style-loader", "css-loader", "stylus-loader"]
      },
      {
        test: /\.less$/,
        loader: ["style-loader", "css-loader", "less-loader"]
      },
      {
        test: /\.scss$/i,
        use: [
          "style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            options: {
              implementation: require("dart-sass")
            }
          }
        ]
      }
    ]
  }
}

开发模式

讲究速度快、轻量。比如直接在html文件中插入style标签而不是抽成css文件等。

综合以上,配置如下:

webpack.config.dev.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const path = require("path")

const base = require('./webpack.config.base.js')

module.exports = {
  ...base,
  mode: "development",
  devtool: "inline-source-map",
  devServer: {
    contentBase: "./dist"
  },
  module: {
    rules: [
      ...base.module.rules,
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"]
      }
    ]
  }
}

生产模式

最终敲定稿。也是要展示给用户的最终版本。

webpack.config.prod.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const path = require("path")

const base = require('./webpack.config.base.js')

module.exports = {
  ...base,
  mode: "production",
  plugins: [
    ...base.plugins,
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css',
      chunkFilename: '[id].[contenthash].css',
      // 是否启用删除有关冲突顺序的警告
      // Enable to remove warnings about conflicting order
      ignoreOrder: false, 
    }),
  ],
  module: {
    rules: [
      ...base.module.rules,
      {
        test: /\.css$/i,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../',
            },
          },
          'css-loader',
        ],
      }
    ]
  }
}