乐趣区

webpack4-学习

webpack 配置学习

以下是我学习 webpack 过程中遇到的问题以及记录。
基本配置可参见官方配置

mode 环境的定义

生产环境:production
开发环境:development
不定义环境:none

entry 入口文件

  • 单入口:"path/to/entry.js",等价于{main:"path/to/entry.js"}。配合路由插件实现多页面。
  • 多入口:{a:"path/to/entryA.js",b:"path/to/entryB.js"}

这里的 "path/to/entry.js",必须使用绝对路径,相对路径会打包报错,找不到文件。可以利用node.jspath模块来自动生成绝对路径。(不需要单独安装 path 库)。代码如下:

const path = require("path");

config = {
  // 这里的 __dirname 是 node.js 的全局变量,指的是当前 js 文件所在绝对路径
  entry: path.resolve(__dirname, "path/to/entry.js")
};

多入口如果这样写 ["path/to/entryA.js","path/to/entryB.js"],会导致打包的 js 只有一个main.js,逻辑全都挂载在页面A,页面B 是空白的。所以不建议这样写。

output 打包输出配置

常用的几个配置选项如下:

  • path:指的是打包文件输出的根目录,必须使用绝对路径。
  • filename:打包后的 js 文件名。例如 "js/[name].[hash:8].bundle.js",这里的[name] 指的是入口 entry 中定义的main a b
  • publicPath:是生成的 js,css,images 等静态资源的引用路径的基本路径。例如 /assets/,那么在打包生成的html 文件中引入的 js,css,images 等静态资源的路径的前面会全部自带 /assets/。还可以使用例如https://cdn.example.com/ 这样的 cdn 配置,这样可以更好的处理生产环境使用 cdn 静态资源的情况。一般不做这项配置也可。

module 处理静态资源的规则

详细可参见官方配置

  • 处理图片文件

    需要安装模块file-loader,url-loader

    具体配置以及说明可参见如下代码:

    {test: /\.(png|svg|jpg|gif|jpeg|tif)$/,
      use: [
        // {
        // webpack 通过 file-loader 处理资源文件,它会将 rules 规则命中的资源文件按照配置的信息(路径,名称等)输出到指定目录,// 并返回其资源定位地址(输出路径,用于生产环境的 publicPath 路径),默认的输出名是以原文件内容计算的 MD5 Hash 命名的
        //   loader: "file-loader",
        //   options: {
        //       outputPath: "images/"
        //   }
        // },
        {
          // 构建工具通过 url-loader 来优化项目中对于资源的引用路径,并设定大小限制,当资源的体积小于 limit 时将其直接进行 Base64 转换后嵌入引用文件,体积大于 limit 时可通过 fallback 参数指定的 loader 进行处理。// 打包后可以看到小于 8k 的资源被直接内嵌进了 CSS 文件而没有生成独立的资源文件
          loader: "url-loader",
          options: {
            limit: 8129, // 小于 limit 限制的图片将转为 base64 嵌入引用位置
            fallback: "file-loader", // 大于 limit 限制的将转交给指定的 loader 处理,开启这里后就无需再单独配置 file-loader options 会直接传给 fallback 指定的 loader
            name: "[name].[ext]",
            outputPath: "images", // 这里是打包后图片所在的位置
            // 这里的 publicPath 作用和 output 配置中的相同,会覆盖 output 中的配置项。// 为了防止 css 中引入图片路径的问题,可以在这里判断如果是开发环境热更新启动模式,改成用根目录的路径 /images
            publicPath: "./images"
          }
        }
      ]
    }
  • 处理字体文件

    和图片文件的处理一样,需要安装 file-loader 模块。

    具体配置可参见如下代码:

    {test: /\.(woff|woff2|eot|ttf|otf)$/,
      use: [
        {
          loader: "file-loader",
          options: {
            outputPath: "css/fonts",
            publicPath: "fonts",
            name: "[name].[hash:8].[ext]"
          }
        }
      ]
    }
  • 处理 css 样式文件

    css不分离的话,就是样式 <style></style> 都在 html 文件的的 head 标签里面。需要安装 style-loader 模块。

    如果 css 分离,则可以异步同时加载 html 文件和 css 文件,可以有效提高加载速度。需要安装 mini-css-extract-plugin 模块(extract-text-webpack-plugin模块不支持 webpack4 以上的版本)。

    另外还需要安装 css-loader 模块。

    postcss-loader模块的作用后面会讲到。

    具体配置以及说明可参见如下代码:

    const miniCssExtractPlugin = require("mini-css-extract-plugin");
    
    {
      test: /\.css$/,
      include: [path.resolve(__dirname, "src")], // 限制打包范围,提高打包速度
      exclude: /node_modules/, // 排除 node_modules 文件夹
      use: [
        // {    // 当配置 MinCssExtractPlugin.loader 后,此项就无需配置,原因看各自作用
        //     loader: "style-loader"  // 将处理结束的 css 代码存储在 js 中,运行时嵌入 `<style>` 后挂载到 html 页面上
        // },
        {
          // 将处理后的 CSS 代码提取为独立的 CSS 文件,可以只在生产环境中配置,但我喜欢保持开发环境与生产环境尽量一致
          loader: miniCssExtractPlugin.loader
        },
        {
          // CSS 加载器,使 webpack 可以识别 css 文件
          loader: "css-loader"
        },
        {
          // 承载 autoprefixer 功能,为 css 添加前缀
          loader: "postcss-loader"
        }
      ]
    }
  • 处理 scss 样式文件

    需要安装的模块同上面 css 一样。另外还需要安装 node-sasssass-loader模块。

    postcss-loader模块这里需要安装 postcss-scss 插件来识别处理 scss 文件。

    具体配置以及说明可参见如下代码:

    {
      test: /\.scss$/,
      include: [path.resolve(__dirname, "src")], // 限制打包范围,提高打包速度
      exclude: /node_modules/, // 排除 node_modules 文件夹
      use: [
        // {    // 当配置 MinCssExtractPlugin.loader 后,此项就无需配置,原因看各自作用
        //     loader: "style-loader"  // 将处理结束的 css 代码存储在 js 中,运行时嵌入 `<style>` 后挂载到 html 页面上
        // },
        {
          // 将处理后的 CSS 代码提取为独立的 CSS 文件,可以只在生产环境中配置,但我喜欢保持开发环境与生产环境尽量一致
          loader: miniCssExtractPlugin.loader
        },
        {
          // CSS 加载器,使 webpack 可以识别 css 文件
          loader: "css-loader"
        },
        {
          // 承载 autoprefixer 功能,为 css 添加前缀
          loader: "postcss-loader",
          options: {parser: "postcss-scss"}
        },
        {
          // 编译 sass,webpack 默认使用 node-sass 进行编译,所以需要同时安装 sass-loader 和 node-sass
          loader: "sass-loader"
        }
      ]
    }
  • 处理 less 样式文件

    需要安装的模块同上面 css 一样。另外还需要安装 lessless-loader模块。

    postcss-loader模块这里需要安装 postcss-less 插件来识别处理 less 文件。

    具体配置以及说明可参见如下代码:

    {
      test: /\.less$/,
      include: [path.resolve(__dirname, "src")], // 限制打包范围,提高打包速度
      exclude: /node_modules/, // 排除 node_modules 文件夹
      use: [
        // {    // 当配置 MinCssExtractPlugin.loader 后,此项就无需配置,原因看各自作用
        //     loader: "style-loader"  // 将处理结束的 css 代码存储在 js 中,运行时嵌入 `<style>` 后挂载到 html 页面上
        // },
        {
          // 将处理后的 CSS 代码提取为独立的 CSS 文件,可以只在生产环境中配置,但我喜欢保持开发环境与生产环境尽量一致
          loader: miniCssExtractPlugin.loader
        },
        {
          // CSS 加载器,使 webpack 可以识别 css 文件
          loader: "css-loader",
          options: {
            // 不处理引入图片的路径问题
            url: false,
            importLoaders: 1
          }
        },
        {
          // 承载 autoprefixer 功能,为 css 添加前缀 浏览器 css 前缀
          loader: "postcss-loader",
          options: {parser: "postcss-less"}
        },
        {
          // 编译 less,webpack 默认使用 less 进行编译,所以需要同时安装 less-loader 和 less
          loader: "less-loader"
        }
      ]
    }
  • 处理 csv|tsv 文件

    需要安装 csv-loader 模块来识别这些文件。

    {test: /\.(csv|tsv)$/,
      use: ["csv-loader"]
    }
  • 处理 xml 文件

    需要安装 xml-loader 模块来识别这些文件。

    {
      test: /\.xml$/,
      use: ["xml-loader"]
    }
  • postcss-loader模块

    PostCSS 是一个允许使用 JS 插件转换样式的工具。这些插件可以检查(lint)你的 CSS,支持 CSS Variables 和 Mixins,编译尚未被浏览器广泛支持的先进的 CSS 语法,内联图片,以及其它很多优秀的功能。

    postcss有许多插件,插件以及配置信息,具体可参见官方说明。

    配置文件默认是postcss.config.js

    处理 .sass 需要安装 postcss-sass 转换器。处理 .scss 文件需要安装 postcss-scss 转换器。处理 .less 文件需要安装 postcss-less 转换器。
    在这里我用了两个插件 autoprefixerprecss

    autoprefixer自动添加各个浏览器 css 前缀,需要 package.json 文件中配置支持的浏览器列表browserslist,才能正确加上所配置浏览器的前缀。具体可查看官方说明。

    precss是让你可以在 css 文件中使用像 scss 文件中的变量以及连接符。具体可查看官方说明。

    或许 cssnano 插件一些人会用,这个是压缩 css 的。我这里压缩 css 用的另外的插件,没有用postcss,后面会讲到。

plugins 插件配置

  • html-webpack-plugin

    这是生成 html 文件的插件,会把打包生成的 css 文件以及 js 文件自动插入到生成的 html 文件中。具体可参见官方说明。

    可以动态生成,适用于多入口。单入口只写一个就可以了。具体配置以及说明可参见如下代码:

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    new HtmlWebpackPlugin({
      // 页面 title 如果使用自定义的摸板,那么摸板 title 标签内容为 <%= htmlWebpackPlugin.options.title %> 才可在生成的 html 文件中正确替换。title: "index",
      // 生成的 html 的文件名以及位置 可添加上相对于打包输出的路径,比如 "views/index.html"
      filename: "index.html",
      // 所使用的自定义摸板 不写表示使用官方默认的摸板
      // 自定义摸板可以添加一些 cdn 公共库,添加公共库还可以用下一小节中的方法
      // template: "src/index.html",
      // 需要插入的 js 模块
      // main 表示入口主文件
      // common 表示提取的公共模块,在 optimization.splitChunks 中定义的
      // vendors 表示提取的第三方模块,即 npm 安装的模块,也是在 optimization.splitChunks 中定义的
      // manifest 运行时的模块,在 optimization.runtimeChunk 中定义的。chunks: ["main", "common", "vendors", "manifest"],
      // 页面图标
      favicon: "src/images/ 备案图标.png", // 配置每个 html 页面的 favicon
      // 压缩选项配置
      minify: {
        // 压缩 HTML 文件
        removeComments: true, // 移除 HTML 中的注释
        collapseWhitespace: true // 删除空白符与换行符
        // css js 已经压缩了,这里不再配置压缩
        // 是否压缩 html 里的 js 我这里使用的 optimization.minimizer 中配置的插件压缩
        // minifyJS: true,
        // 压缩 html 里的 css 我这里使用的 optimization.minimizer 中配置的插件压缩
        // minifyCSS: true // 压缩内联 css
      },
      // 请求 js css 资源时,附带哈希值 这对缓存清除(cache busting)十分有用。hash: true
    })
  • 第三方库的公共引入 暴露全局 不用单独 import

    这里是引入公共的第三方模块,并暴露全局变量。使用时不用单独引入,可以直接使用暴露的全局变量。

    也可以使用上一小节中提到的 html 摸板中插入 cdn 公共库链接的方法,这样可以减少自己服务器的压力。

    具体配置以及说明可参见如下代码:

    const webpack = require("webpack");
    
    // _是暴露的全局变量名称 "lodash" 是引入的公共第三方库
    new webpack.ProvidePlugin({_: "lodash"})
  • mini-css-extract-plugin

    这个插件在处理 css,scss,less 文件的时候也有说明,这里主要是对打包输出 css 文件的配置。具体可参见官方说明。

    具体配置以及说明可参见如下代码:

    new miniCssExtractPlugin({
      // 打包后的 css 文件输出路径以及名称
      filename: "css/[name].[hash:8].css"
    })
  • clean-webpack-plugin

    这个插件的作用是每次打包,清理过期文件。具体可参见官方说明。

    具体配置以及说明可参见如下代码:

    const {CleanWebpackPlugin} = require("clean-webpack-plugin");
    
    // plugins 中简单的插入这一句即可
    new CleanWebpackPlugin()
  • purifycss-webpack

    这个插件的作用是打包过程中消除无用多余的 css 样式。需要配合glob 使用。

    具体配置以及说明可参见如下代码:

    const glob = require("glob");
    const PruifyCSSPlugin = require("purifycss-webpack");
    
    new PruifyCSSPlugin({
      // src 下所有的 html
      // paths: glob.sync(path.join(__dirname, "src/*.html"))
      // src 下所有的 js
      paths: glob.sync(path.join(__dirname, "./src/**/*.js"))
    })

optimization

优化打包的配置。具体可参见官方说明。

  • splitChunks

    找到 chunk 中共享的模块, 取出来生成单独的 chunk。

    具体配置以及说明可参见如下代码:

    splitChunks: {
      chunks: "all", // async 表示抽取异步模块,all 表示对所有模块生效,initial 表示对同步模块生效
      cacheGroups: {
        vendors: {
          // 抽离第三方插件
          test: /[\\/]node_modules[\\/]/, // 指定是 node_modules 下的第三方包
          // 打包后的模块文件名称
          name: "vendors",
          priority: -10 // 抽取优先级
        },
        commons: {
          // 抽离自定义工具库
          name: "common",
          priority: -20, // 抽取优先级
          minChunks: 2, // 表示将引用模块如不同文件引用了多少次,才能分离生成新 chunk
          minSize: 0 // 将引用模块分离成新代码文件的最小体积
        }
      }
    }
  • minimizer

    代码压缩 仅当 mode='production' 时生效。

    具体配置以及说明可参见如下代码:

    const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
    const TerserPlugin = require("terser-webpack-plugin");
    
    minimizer: [
      // 对生成的 CSS 文件进行压缩
      new OptimizeCssAssetsWebpackPlugin({
        cssProcessorPluginOptions: {
          // options 去掉注释
          preset: ["default", { discardComments: { removeAll: true} }]
        }
      }),
      // 压缩 js
      new TerserPlugin({minify: (file, sourceMap) => {
          // https://github.com/mishoo/UglifyJS2#minify-options
          const uglifyJsOptions = {
            /* your `uglify-js` package options */
            output: {
              // 去掉注释
              comments: false
            },
            compress: {
              // 去掉控制台打印
              drop_debugger: true,
              drop_console: true
            }
          };
    
          if (sourceMap) {
            uglifyJsOptions.sourceMap = {content: sourceMap};
          }
    
          return require("uglify-js").minify(file, uglifyJsOptions);
        }
      })
    ]
  • runtimeChunk

    webpack 运行时代码创建单独的 chunk

    详细说明可参见官方说明

    runtimeChunk: {name: "manifest"}

代码热更新 浏览器自动刷新

开发环境的配置,可参见 webpack 开发环境。

自动编译官方列举了三种方式,这里我使用的是 webpack-dev-server 模块。详细配置项可参见官方说明。

具体配置以及说明可参见如下代码webpack.config.dev.js

const chalk = require("chalk"); // 改变命令行中输出日志颜色插件
const ip = require("ip").address();

// source-map 控制台追寻到源代码的文件。devtool: "inline-source-map",
devServer: {
  // 运行时的目录
  contentBase: path.resolve(__dirname, "dev"),
  // 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。historyApiFallback: true,
  // 指定使用一个 host。默认是 localhost。host: ip,
  // 控制台显示启动过程进度
  progress: true,
  // 当出现编译器错误或警告时,在浏览器中显示全屏覆盖。默认情况下禁用。overlay: true,
  // 自动打开浏览器
  open: true,
  // 启用 webpack 的模块热替换特性
  hot: true,
  after() {console.log(chalk.cyan(`http://${ip}:${this.port} 已成功打开 `));
  }
}
// plugins 配置项中添加 new webpack.HotModuleReplacementPlugin(),用于模块的热更新。

devServer中的配置项一般也可以在 npx 命令中配置使用,这样可以使用一个 config 文件,来条件编译即可。

package.json中的 npx 命令

示例:

"scripts": {
  "test": "echo \"Error: no test specified\"&& exit 1",
  "watch": "webpack --watch",
  "start": "webpack-dev-server --config=webpack.config.dev.js",
  "dev": "cross-env NODE_ENV=development webpack --progress --colors --devtool cheap-module-source-map",
  "build": "webpack --progress --colors"
}
  • cross-env模块

    可在命令中定义环境变量。cross-env NODE_ENV=development,在这里定义了环境变量,就可以在配置文件 webpack.config.js 中获得并使用这个变量,以处理条件编译。

    获得环境变量:const env = process.env.NODE_ENV

退出移动版