首页 >> 大全

Webpack 的配置设置

2023-09-14 大全 24 作者:考证青年

前言

大概有和我一样的同学,毕业后工作的一段时间内都对项目配置文件产生抗拒的心理,每天只敢npm run serve/dev,生怕动了些什么,它就跑不动了...

这种行为大概持续了大半年的时间,只要涉及项目配置文件,全权丢给我的导师,这种不负责任的行为也被多次批评不够上进。

后续的转变,或许是因经验的增长,亦或是想成为更优秀的工程师,才开始慢慢上手并实践于项目中。

废话说完了,前言也凑完了,但主要目的还是不想大家重蹈我的覆辙 ~

文章内容围绕 配置进行实践总结,希望看完之后,能让你觉得 没那么难。

是什么

是 的静态模块打包工具,它在内部从一个或多个入口点构建依赖图,然后将项目中所需的每一个模块组合成一个或多个。

从定义可知: 开箱只支持 文件类型,其实还包含 JSON 文件类型。其他静态资源需要通过 来支持,后续会讲解。

概念 初始化项目

新建文件夹。

npm init -y生成 .json 文件。

npm i -cli --save-dev安装 依赖。

安装的 版本,版本不同可能会导致后续步骤出错(可在评论区交流 ~)。

:5.61.0

-cli:4.9.1

node:14.15.0

项目根目录新建src文件夹,再在文件夹下新建index.js和util.js。

// util.js
export function helloWebpack {return 'hello webpack'
}// index.js
import { helloWebpack } from './utils'document.write(helloworld())
复制代码

新建个..js

const path = require('path')module.exports = {entry: './src/index.js', // 入口文件output: {  // 出口文件path: path.join(__dirname, 'dist'),filename: 'bundle.js'},mode: 'production' // 当前构建环境
}
复制代码

在.json中的添加打包命令,执行npm run build。

"scripts": {"test": "echo \"Error: no test specified\" && exit 1",
+  "build": "webpack"
},
复制代码

打包完成,根目录下会多出一个dist文件夹 ~

Tips:npm 可运行 原理是 .json 文件可以读取/.bin目录下的命令,而命令是在模块局部安装时创建的软链接。

入口(entry)

初始化项目配置中的entry字段指定 打包入口,注意入口文件仅支持 文件(可参考官网的依赖图)。

entry 配置有两种情况:单页面 和 多页面。

单页面配置,entry 是一个字符串。

module.exports = {entry: './src/index.js'
}
复制代码

多页面配置下,entry 是一个对象。

module.exports = {entry: {app: './src/app.js',app2: './src/app2.js'}
}
复制代码

出口()

初始化项目配置中的字段指定 文件打包出口,以及命名出口文件。

出口与入口配置一样具备两种配置情况:单页面 和 多页面。

在配置前先介绍下 path 库下两个常用 api 的用法。

path.:顺序从右往左,若字符以 / 开头,不拼接前面的路径;若以 ../ 开头,拼接前面的路径,且不包含最后一节的路径;若以 ./ 开头或者没有符号,则拼接前面的路径。

path.join:顺序从右往左,只是拼接各个 path 片段。

单页面配置, 配置如下。

const path = require('path')module.exports = {entry: './src/index.js',output: {filename: 'bundle.js',path: path.join(__dirname, 'dist')}
}
复制代码

多页面配置,[name]中 name 变量与 entry 对象的 key 对应。

const path = require('path')module.exports = {entry: {app: './src/app.js'app2: './src/app2.js'},output: {path: path.join(__dirname, 'dist'),filename: [name].js}
}
复制代码

因 只支持 和 JSON 文件类型,所以提供 帮助 去处理其不支持的文件类型,并将它们转化为有效模块,以供应用程序使用,以及被添加到依赖图中。

常见的 如下所示。

名称描述

babel-

处理 es6+ 语法,将其编译为浏览器可执行的 js 语法

vue-

支持 .vue 文件的加载和解析

style-

把 css 以 style 标签插入到 html 文件中

css-

支持.css文件的加载和解析

sass-/less-

将sass/less文件转换成css

file-

图片、字体等静态资源打包

url-

类似于 file-,当文件低于限定值转

ts-

将 Ts 转换成 Js

raw-

将文件以字符串的形式导入

有两个属性:

test:正则匹配文件类型。

use:文件转换使用的 。

基本使用如下所示。

const path = require('path')module.exports = {module: {rules: [{test: /\.txt$/,  // 匹配 txt 文件类型use: 'raw-loader' // 使用 raw-loader}]}
}
复制代码

插件()

插件用于扩展 的功能,可用于 文件的优化、资源管理和环境变量注入,运行可在打包的整个周期。

常见的 如下所示。

名称描述

从 v4 开始,移除了 ,取而代之的是.。作用是提取公共模块,减小 体积,优化首屏渲染

清理构建目录

配置设置文件是什么_配置设置文件怎么生成的_

将文件或者文件夹拷贝到构建的输出目录

从 v4 开始,移除了 ugin,取而代之的是。作用是将 css 从 文件里提取成一个独立的 css 文件,以 link 标签的形式注入 html 中

lugin

压缩 CSS 代码

模块热更新

创建 html 文件,并将静态文件插入到这个 html 文件中

压缩 js,从 v4 开始,已经内置。

压缩 js,从 v5 开始,已经内置。

的使用比较简单,拿 为例

const path = require('path')module.exports = {plugins: [new HTMLWebpackPlugin({template: './src/index.html'})]
}
复制代码

模式(mode)

区分当前构建环境是生产、还是开发,默认值是。

值有 、、none 三种。

实践

基本的内容大概都了解了,现在我们开始实践部分 ~

创建 html 文件

src 目录下新建 html 模板文件,后续讲解案例会以 Vue 为中心,所以模板内容如下。


复制代码

后续打包创建 html,并将静态资源文件插入到该 html 的都得益于 。

安装npm i html-- \-D。

简单配置...

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js', output: { path: path.join(__dirname, 'dist'),filename: 'bundle.js'},mode: 'production',plugins: [new HtmlWebpackPlugin({template: './src/index.html', // 模板 html 文件路径filename: 'index.html', // 指定打包文件名称inject: true, // 向 html 模板注入所有静态资源})]
}
复制代码

详细配置参考 官方详细配置文档[2]。

支持 ES6+

借助 babel 相关的库,将 ES6+ 的代码转换为 ES5,从而兼容更多的浏览器环境。

安装 babel 相关的库函数

npm i @babel/core @babel/-env babel- \--save-dev

..js 文件中添加对 js 文件的解析。

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/index.js',output: {path: path.join(__dirname, 'dist'),filename: 'bundle.js'},module: {rules: [{test: /\.js$/,exclude: /node_modules/, // 除去依赖部分use: 'babel-loader'}]},mode: 'production',plugins: [new HtmlWebpackPlugin({template: './src/index.html', filename: 'index.html', inject: true, })]
}
复制代码

根目录下新建 . 配置文件,并安装依赖:npm i core-js@3 \--save-dev。

{"presets": [["@babel/preset-env", {"useBuiltIns": "usage", // 在文件运用到新特性的位置单独按需引入"corejs": 3,  // corejs 核心库的版本"targets": "> 0.25%, not dead" // 浏览器支持的范围}]]
}
复制代码

配置帮助我们处理 、Map、Set、等新特性,core-js (@babel/ 已在 7.4.0 中弃用)是处理新特性的依赖库。

更改 index.js 文件,npm run build进行打包。

const a = () => Promise.resolve(1)
const getData = async () => {const res = await a()console.log(res)
}
getData()
复制代码

打包完成后,可访问 index.html,验证是否正确。

扩展下,经babel 官网[3]Try it out 按上述配置将 index.js 代码转换。

"use strict";function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }var a = function a() {return Promise.resolve(1);
};var getData = /*#__PURE__*/function () {var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {var res;return regeneratorRuntime.wrap(function _callee$(_context) {while (1) {switch (_context.prev = _context.next) {case 0:_context.next = 2;return a();case 2:res = _context.sent;console.log(res);case 4:case "end":return _context.stop();}}}, _callee);}));return function getData() {return _ref.apply(this, arguments);};
}();getData();
复制代码

可发现,转换 async 时,babel 自定义了 函数来辅助。由此,可知若项目文件过多,每个文件只要有 async ,那项目就会在每个最终打包文件重复定义当前函数。

优化一下 ~

安装@babel/--以及@babel/-。

更改 babel 相关配置,可添加index.html自行测试。

{"presets": [["@babel/preset-env"]],"plugins": [["@babel/plugin-transform-runtime", { "corejs": 3 }]]
}
复制代码

Try it out 添加相关插件转换代码如下。

"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));require("core-js/modules/es.object.to-string.js");require("core-js/modules/es.promise.js");var a = function a() {return Promise.resolve(1);
};var getData = /*#__PURE__*/function () {var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {var res;return _regenerator["default"].wrap(function _callee$(_context) {while (1) {switch (_context.prev = _context.next) {case 0:_context.next = 2;return a();case 2:res = _context.sent;console.log(res);case 4:case "end":return _context.stop();}}}, _callee);}));return function getData() {return _ref.apply(this, arguments);};
}();
复制代码

从转换代码看出,优化后,由原先的定义函数改为从一个统一的模块中引入。

支持 Vue

安装 Vue,npm i vue \-S。

安装相关插件,npm i vue- vue-- \-D。

注意 vue-- 需和 vue 版本需一致,我的实验版本为v2.6.14。插件主要用于将 Vue 模板编译为渲染函数,避免运行时编译开销和 CSP 限制。

CSP( )网页安全政策,帮助检测和缓解某些类型的攻击,包括跨站脚本(XSS)和 数据注入等攻击。

新建 main.js 和 App.vue 文件。

// main.js
import Vue from 'vue'
import App from './App.vue'export default new Vue({render: h => h(App)
}).$mount('#app')
复制代码

// App.vue


复制代码

更改..js文件。

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
+ const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
- entry: './src/index.js',
+ entry: './src/main.js',output: {path: path.join(__dirname, 'dist'),filename: 'bundle.js'},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader'}},
+   {
+     test: /\.vue$/,
+     loader: 'vue-loader'
+   }]},mode: 'production',
+ plugins: [
+   new VueLoaderPlugin(),new HtmlWebpackPlugin({template: './src/index.html',filename: 'index.html',inject: true})]
}
复制代码

删除旧包,执行npm run build重新打包,打开 dist 文件夹下的 index.html,验证是否正常显示 Hello Vue。

支持 CSS 及 SCSS

解析 css 文件需要运用 css- 进行加载,并且将其转换成 对象,再通过 style- 将样式通过 style 标签插入到 head 标签中。

安装相关插件,npm i css- style- \-D。

..js文件中添加 css 文件解析规则。

{test: /\.css$/,use: ['style-loader','css-loader']
}
复制代码

这里有个小的知识点: 是链式调用的,执行顺序也是从右到左的。因此,需要先写 style-,再写 css- 。

新建 main.css 文件,再在 App.vue 文件中引用,完成后,可打包进行测试 ~

// main.css
.message {color: red;
}
复制代码

// App.vue


复制代码

现有项目,大部分也都使用了 CSS 预处理器,这里以 SCSS 为例。

安装相关的插件npm i sass sass- \-D。

安装完成后,将 main.css 改成 main.scss , App.vue 中的样式引入更改为 './main.scss'。

..js文件中添加对 SCSS 文件的加载解析。

{test: /\.scss$/,use: ['style-loader','css-loader','sass-loader']
}
复制代码

完成后,删除旧包后重新打包,测试一下~

支持图片、字体

_配置设置文件怎么生成的_配置设置文件是什么

可以使用 file- 去解析图片、字体。

安装npm i file- \-D。

src 目录下新建个 和 fonts 文件夹, 文件夹下添加一张图片,fonts 文件夹下引添加字体文件。

在App.vue中引入。



复制代码

在 main.scss 文件夹下添加字体的定义。

@font-face {font-family: 'Manrope-SemiBold';src: url('./fonts/Manrope-SemiBold.ttf');
}
.message {color: red;font-family: 'Manrope-SemiBold';
}
复制代码

..js文件增加图片和字体文件的加载解析。

 {test: /.(png|jpg|gif|jpeg)$/,use: ['file-loader']}, {test: /\.(woff|woff2|eot|ttf|otf)$/,use: ['file-loader']}
复制代码

完成后,删除旧包,打包访问的 html 文件可验证图片和字体文件是否正常加载。

在 部分中有提到 url-,其底层基于 file-,在加载解析图片和文件基础上提供可设置较小资源转 格式的功能。

转 可减少 HTTP 请求。所以大文件是不适合转 ,容易导致首屏空白现象。

使用如下所示,小于 10KB 的转 格式。

{test: /.(png|jpg|gif|jpeg)$/,use: [{loader: 'url-loader',options: {limit: 10240}}]
}
复制代码

熟悉 v5 的,可能了解 的资源模块,无需配置额外的 ,如 file-、url-、raw-。

类型描述

asset/

发送一个单独的文件并导出 URL。之前通过使用file-实现。

asset/

导出一个资源的 data URI。之前通过使用url-实现。

asset/

导出资源的源代码。之前通过使用raw-实现。

asset

在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用url-,并且配置资源体积限制实现。

更改下述代码。

{test: /.(png|jpg|gif|jpeg)$/,
-  use: ['file-loader'],
+  type: 'asset/resource',
+  generator: {
+    filename: '[name][hash:8].[ext]'
+  }
}, 
{test: /\.(woff|woff2|eot|ttf|otf)$/,
- use: ['file-loader'],
+  type: 'asset/resource',
+  generator: {
+    filename: '[name][hash:8].[ext]'
+  }
}
复制代码

开发服务器

搭建开发服务器,避免需先打包后验证的傻瓜式操作。同时,配置热更新,实时渲染页面,纠正开发阶段的低级错误。

安装npm i -dev- \-D。

为了区分 生产 和 开发 模式,新建.dev.js和.prod.js文件。

复制一份..js,粘贴到.dev.js。

更改部分内容:

mode 配置项更改为 development。

添加 devServer 配置,配置热更新,hot 为 true 的情况下会自动引入`HotModuleReplaceMentPlugin`插件。

devServer: {port: 3000, // 端口hot: true, // 开启热更新open: true // 启动开启浏览器
}
复制代码

同样的操作,粘贴到.prod.js,无需做改动,完成后,删除原有的..js。

最后,更改下.json文件中的字段。

scripts: {"dev": "webpack-dev-server --config webpack.dev.js","build": "webpack --config webpack.prod.js","test": "echo \"Error: no test specified\" && exit 1",
}
复制代码

完成后,可执行npm run dev验证,是否正常显示页面且热更新生效。

添加文件指纹

文件指纹指打包后输出文件名的后缀,其有版本管理,清除缓存的作用。

文件指纹有三种类型。

hash: 与整个项目构建有关系,项目文件更改,整个项目构建的 hash 值也会更改。

: 和 打包的 chunk 有关,不同的 entry 会生成不同的 值。

:根据文件内容来定义 hash,文件内容不变,则 不变。

文件指纹的作用主要还是运用在测试、生产环境。所以,我们只需要更改.prod.js文件即可。

针对 js 文件类型,设置 的 ,使用的是[:8]。

output: {path: path.join(__dirname, 'dist'),
+ filename: '[name][chunkhash:8].js'
- filename: 'bundle.js'
}
复制代码

针对 css 文件类型,目前是使用 style-,其将 css 构建到 js 文件中,然后在 js 文件加载的时候再以 style 标签插入到 html 中。那如何提取独立的 CSS 文件呢?那就要谈到插件。

安装npm i mini-css-- \-D,.prod.js 文件引入const = ('mini-css--')。

添加 插件,且使用 变量。

plugins: [new VueLoaderPlugin(),
+  new MiniCssExtractPlugin({
+    filename: '[name][contenthash:8].css'
+  }),new HtmlWebpackPlugin({template: './src/index.html',inject: true,filename: 'index.html'})
]
复制代码

style- 与 冲突,替换 style- 为 .

{test: /\.css$/,use: [
-   'style-loader'
+    MiniCssExtractPlugin.loader,'css-loader']
}, 
{test: /\.scss$/,use: [
-   'style-loader'
+    MiniCssExtractPlugin.loader,'css-loader','sass-loader']
}, 
复制代码

针对图片、字体等类型,设置相关解析 的配置参数,使用的是[hash:8]。

{test: /.(png|jpg|gif|jpeg)$/,use: [{loader: 'file-loader',options: {name: '[name][hash:8].[ext]'}}]
}, 
{test: /\.(woff|woff2|eot|ttf|otf)$/,use: [{loader: 'file-loader',options: {name: '[name][hash:8].[ext]'}}]
}    
复制代码

代码压缩

v5 版本开始,开箱即带最新版本的 --。若想自定义配置,仍需安装。

若自定义,安装npm i -- \-D。

配置如下,需使用 (优化)字段,该字段从 v4 开始,根据不同的mode执行不同的优化。

optimization: {minimize: true, // 告知 webpack 使用 TerserPlugin 或其他使用 optimization.minimizer 定义的压缩插件 minimizer: [new TerserPlugin()]
}
复制代码

再来讲 css 代码压缩,v5 推荐使用 插件,与 gin 插件一样,但在 和 中使用查询字符串会更加准确,支持缓存和并发模式下并行,且内置了 ,无需额外安装。

安装npm i css--- \-D。

配置如下。

optimization: {minimizer: [new CssMinimizerPlugin()]
}
复制代码

执行npm run build,出现报错。

根据提示,安装 (v8.3.11)解决问题。

image.png

清除构建目录

每次构建时若不清理旧包,会造成构建的输出目录 文件越来越多,因此,清除是必然的操作。为了避免构建前手动删除 dist 目录,同样需要插件 去自动删除旧包。

安装npm i clean-- \-D。

.prod.js的 字段添加 插件。

头部引入const { } = ('clean--')。

plugins: [new VueLoaderPlugin(),new MiniCssExtractPlugin({filename: '[name][contenthash:8].css'}),new HtmlWebpackPlugin({template: './src/index.html',inject: true,filename: 'index.html'}),
+  new CleanWebpackPlugin()
]
复制代码

根据 官网 v5.2+ 增加了 的 clean 字段,具备同样的功能,无需额外安装 插件。

配置如下。

output {path: path.join(__dirname, 'dist'),filename: '[name][chunkhash:8].js',
+  clean: true
}
复制代码

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了