上一节我们介绍了如何对css做兼容性处理,以及如何将代码中的css单独提取成css文件,并对其进行压缩处理。结合前几个章节的内容,我们已经知道了在webpack中如何对js以及css文件处理。那么除了js与css文件外,类似于 html资源图片资源 以及 其他的资源 又该怎么去处理呢?这一节我们一起来看一下~

打包html资源

要想对html资源进行打包,我们需要用到一个插件:html-webpack-plugin。这个插件的作用主要是生成html文件,并自动将output生成的文件引入

安装

yarn add -D html-webpack-plugin

配置

安装完成后,我们需要在 webpack.config.js 中引入插件,并配置到 plugins 选项中:

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/js/index.js',
  // 输出
  output: {
    filename: 'js/[name].[contenthash:10].js',
    //   __dirname表示当前文件所在目录的绝对路径
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [/*...*/]
  },
  plugins: [
    new HtmlWebpackPlugin()
  ],
  mode: 'development'
}

配置完成后,执行打包命令,会看到在 build 目录下多出了一个 index.html 文件。这个文件就是通过 html-webpack-plugin 插件生成出来的。

js与css文件的自动引入

打开生成的 index.html 文件,我们可以看到打包出来的js文件被自动引入了:

还记的我们上一节中提到的提取css文件的操作么?如果我们将css文件也提取出来之后也会被自动引入到 index.html 文件中么?我们一起来试一试,将上节中的配置写入进来:

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: './src/js/index.js',
  // 输出
  output: {
    filename: 'js/[name].[contenthash:10].js',
    //   __dirname表示当前文件所在目录的绝对路径
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [
    	{
        // 匹配.js文件
        test: /\.js$/,
        // 需要忽略掉node_modules,不然会对其中的内容也做检查, 会降低打包的性能
        exclude: /node_modules/,
        // 使用babel-loader
        use: [
          {
            loader: 'babel-loader',
            // loader的相关配置
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    // 指定按需加载
                    useBuiltIns: 'usage',
                    // 指定core-js的版本
                    corejs: {
                      version: 3,
                    },
                    // 指定兼容的浏览器版本
                    targets: {
                      chrome: '60',
                      firefox: '60',
                      ie: '9',
                      safari: '10',
                      edge: '17',
                    },
                  },
                ],
              ],
            },
          },
        ],
      },
      {
        test: /\.s[ac]ss/,
        exclude: /(node_modules|build)/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ],
      },
    ]
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/index.[contenthash:10].css', // 设置css文件的输出路径
    }),
  ],
  mode: 'development'
}

此时我们再次执行打包命令,之后打开生成的 index.html 文件,我们可以看到提取出来的css文件也会被引入进来:

配置自定义html模板

在上面的栗子中,我们只是单纯的使用了 html-webpack-plugin 这个插件。在不传入任何配置的情况下,这个插件会生成一个最简单的html文件。如果我们对生成的html文件有定制化的需求,此时,我们可以给这个插件传入相应的参数,用来声明生成html文件时所需要使用的模板。

在传入配置之前,我们先在src目录下创建一个 index.html 文件,用来定义我们自定义的页面模板:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack-image</title>
</head>
<body>
  <p>我的自定义模板</p>
</body>
</html>

之后,我们给插件传入如下配置:

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  /* ... */
  plugins: [
    new HtmlWebpackPlugin({
    	template: resolve(__dirname, 'src/index.html')
    })
  ]
  /* ... */
}

此时,当我们再次执行打包命令后,点开生成的html文件:

我们可以看到,在生成的html文件中,存在我们自定义的内容,与此同时,css与js文件也会被自动引入进来。

注意

由于js与css文件会被自动引入进来,所以我们在模板中不需要手动引入css与js,否则会出现重复引入的情况!

指定html文件的生成目录

除此之外,我们也可以指定html文件生成的路径:

const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  /* ... */
  plugins: [
    new HtmlWebpackPlugin({
       template: resolve(__dirname, 'src/index.html'),
       filename: 'html/index.html'
    })
  ]
  /* ... */
}

配置完成后,html文件就会被打包至 build/html 路径下,文件名为 index.html

打包图片资源

图片资源主要有两个来源,一个是来自于html文件中,另一个是来源于css文件中。针对这两种不同的情况,处理的方式也各有不同。

打包css文件中的图片

要想打包css文件中的图片,我们需要用到一个loader工具:url-loader。这个loader的作用是处理css中的图片(其依赖于file-loader,所以也要下下来)。

安装

yarn add -D url-loader file-loader

配置

安装完成后,我们在 webpack.config.js 中加入以下配置:

/* ... */
rules: [
  {
    test: /\.(jpeg|png|gif|jpg)$/,
    loader: 'url-loader',
    options: {
      // 限制图片大小为8kb,含义是当图片的大小小于8kb时,会被编译成base64的形式写入样式,而超过8kb则会引入图片。
      // 优点:减少请求
      // 缺点:base64之后的大小可能会比原先图片的大小更大
      limit: 8 * 1024, 
      // 设置打包出来的图片名称,其中hash表示hash值,10表示截取hash值的前10位,ext表示保留图片原本的后缀名
      // 可以设置图片打包出去的路径
      // 比如'img/[hash:10].[ext]'表示将图片打包到build下的img文件夹中
      // 注意:1、此处的路径设置是相对于build文件夹的,如果设置'../[hash:10].[ext]'就是打包到build的上一级目录。
      // 2、这里设置的路径,也是最后css文件中引入的路径。比如设置的'img/[hash:10].[ext]',那在css中引入的就是:background: url(img/....)。
      name: '[hash:10].[ext]'
    }
  }
]
/* ... */

打包html文件中的图片

处理html中的图片文件需要使用到另外一个loader:html-loader。这个loader的作用是引入html文件中的img,从而可以使其被url-loader处理

安装

yarn add -D html-loader

配置

安装完成后,我们只需要在 webpack.config.jsrules 配置项中加入以下内容:

{
  test: /\.html$/,
  loader: 'html-loader'
}

然后在上述的 src/index.html 模板中,引入一张图片:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack-image</title>
</head>
<body>
  <p>我的自定义模板</p>
  <img src="./images/luoxiaohei1.jpeg" alt="">
</body>
</html>

之后运行打包命令,打开生成的html文件,我们即可看到引入的图片。

注意

如果图片的显示路径是"[Object Module]",原因是url-loader默认试用ES6的方式解析,而html-loader引入的图片是commonjs,所以在解析时会报错。此时需要将url-loader的 esModule 属性设置为fasle:

{
  test: /\.(jpeg|png|gif|jpg)$/,
  loader: 'url-loader',
  options: {
    limit: 8 * 1024,
    name: '[name].[hash:10].[ext]',
    esModule: false
  },
},

打包其他资源

打包其他资源(比如字体文件等不需要进过loader处理的文件)就是将其他资源原封不动原样输出。这需要用到 file-loader。在上述对css中的图片进行打包时,我们已经安装过这个包了。接下来的配置很简单 ,只需要在 webpack.config.js 中加入如下配置:

{
    exclude: /\.(html|js|css|sass)$/,
    loader: 'file-loader',
    options: {
      name: '[name]-[hash:10].[ext]'
    }
}

与其他loader配置不同的是,我们不需要用test的属性去匹配具体格式的文件,而是通过exclude的方式将不需要处理的文件排除出去,之后通过file-loader进行处理输出即可。

devServer

在日常开发过程中,我们通常会在本地启动一个服务用来做一些诸如自动编译,自动刷新等等的自动化操作。此时,我们需要用到 devServer。相对于打包输出文件到对应目录,devServer不会有任何文件输出

安装

yarn add -D webpack-dev-server

配置

webpack.config.js 文件下,我们加入以下配置:

const { resolve } = require('path')

module.exports = {
  entry: './src/js/index.js',
  // 输出
  output: {
    filename: 'js/[name].[contenthash:10].js',
    //   __dirname表示当前文件所在目录的绝对路径
    path: resolve(__dirname, 'build'),
  },
  module: {
    rules: [/*...*/]
  },
  plugins: [
    /* ... */
  ],
  mode: 'development',
  devServer: {
    // 设置运行的项目路径
    contentBase: resolve(__dirname, 'build'),
    // 启动后打开浏览器
    open: true,
    // 启动gzip压缩
    compress: true,
    // 端口配置
    port: 3000
  }
}

启动

配置完成后,我们可以在控制台中输入启动命令(也可以将启动命令写入 package.json 文件中):

npx webpack-dev-server

启动完成后,会自动唤起浏览器,打开端口为3000的本地页面,并且当我们对代码进行修改时,它会自动监听代码的改动进行自动编译,并刷新页面。