如下是我学习webpack
过程当中遇到的问题以及记录。
基本配置可参见官方配置javascript
mode
环境的定义生产环境:production
开发环境:development
不定义环境:none
css
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.js
的path
模块来自动生成绝对路径。(不须要单独安装path
库)。代码以下:html
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
打包输出配置经常使用的几个配置选项以下:java
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
处理静态资源的规则详细可参见官方配置node
处理图片文件webpack
须要安装模块file-loader
,url-loader
。git
具体配置以及说明可参见以下代码:github
{ 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" } } ] }
处理字体文件web
和图片文件的处理同样,须要安装file-loader
模块。npm
具体配置可参见以下代码:
{ 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-sass
和sass-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
同样。另外还须要安装less
和less-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
转换器。
在这里我用了两个插件autoprefixer
和precss
。
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
最后可参见个人一个小demo:https://gitee.com/wtto00/webpack-demo