
开始
webpack学习计划终于来了
一直感觉学webpack有些困难,拖了好久,面试了头条和腾讯都同时问到了webpack,webpack也该提上日程了
安装
1 | npm i webpack webpack-cli -D |
package.json添加
1 | "scripts": { |
相关文档:https://www.webpackjs.com/guides/installation/#%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6
常用名称
- ‘[name]’ 当前文件名称
- ‘[contenthash]’ 用于缓存问题,根据内容生成hash名称
- ‘[ext]’ 文件后缀名
- ‘[hash]’ 随机hash生成
入口Entry
单个入口文件
1
2
3{
entry:'./app.js'
}多个入口文件
1
2
3
4
5
6
7{
entry: {
home: './home.js',
about: './about.js',
contact: './contact.js',
},
}
出口output
1 | { |
懒加载
使用import语法,可以实现打包后项目需要的时候再加载,语法为import(‘模块名称’).then({deafult:模块名称}=>{})
- import(‘/ * webpackChunkName: “jqueryA” * /‘) webpackChunkName指定懒加载js的文件名称
- import(‘/ * webpackPrefetch: true * /‘) 预加载
1 | (function(){ |
预加载与预获取
预获取
1
import(/* webpackPrefetch: true */ './path/to/LoginModal.js');
预加载
1
import(/* webpackPreload: true */ 'ChartingLibrary');
测试中发现预加载和普通的import引入就没有多大的区别 了
两者区别
- preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
- preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
- preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
- 浏览器支持程度不同。
resolve
alias 创建
import
或require
的别名,来确保模块引入变得更简单1
2
3
4
5
6resolve: {
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/'),
},
},extensions尝试按顺序解析这些后缀名。如果有多个文件有相同的名字,但后缀名不同,webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀。
1
2
3resolve: {
extensions: ['.js', '.json', '.wasm'],
},mainFiles 解析目录时要使用的文件名。
1
2
3resolve: {
mainFiles: ['index','main'],
},参考链接:https://webpack.docschina.org/configuration/resolve/#resolvemainfiles
Loader
- asset 自动选择base64图还是文件
- asset/source 文件输出
- asset/inline base64图片输出
1 | { |
postcss-loader 为css打包时,添加样式前缀 参考链接:https://webpack.docschina.org/loaders/postcss-loader/
- 方法1 webpack.config.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
28module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
],
},
},
},
],
},
],
},
};- 方法2 或者使用 PostCSS 本身的 配置文件:
postcss.config.js
1
2
3
4
5
6
7
8
9
10module.exports = {
plugins: [
[
'postcss-preset-env',
{
// 其他选项
},
],
],
};Loader 将会自动搜索配置文件。
webpack.config.js
1
2
3
4
5
6
7
8
9
10module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
],
},
};加大难度 ,为css添加前缀后,提出一个单独的css文件,并放置在css文件夹中
1
2
3
4
5
6
7
8
9
10
11
12
13module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
'postcss-loader'
],
},
]
},
Mode
- development 开发模式
- production 生产模式
production 模式下,会自动清理console.log
缓存
普通缓存
1 | output: { |
利用[contenthash]实现针对文件内容生成的文件名,当文件内容修改,hash会不同,也就解决浏览器缓存的问题,可以即时刷新。当文件内容未修改,contenthash值相同,浏览器会使用缓存文件
缓存第三方文件
将第三方库(library)(例如 lodash
或 react
)提取到单独的 vendor
chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用 client 的长效缓存机制,命中缓存来消除请求,并减少向 server 获取资源,同时还能保证 client 代码和 server 代码版本一致。 这可以通过使用 SplitChunksPlugin 示例 2 中演示的 SplitChunksPlugin
插件的 cacheGroups
选项来实现。我们在 optimization.splitChunks
添加如下 cacheGroups
参数并构建:
1 | optimization: { |
原文参考https://webpack.docschina.org/guides/caching/#output-filenames
打包CSS、js、img到各自文件总结
1 | const path = require('path'); |
问题?使用htmlWebpackPlugin template时,使用到了图片,打包后图片不显示
devTool对比
值 | 是否可以追踪报错信息 | 备注 |
---|---|---|
eval | 是 | 构建:快速; 重建:最快,默认值 具有最高性能的开发构建的推荐选择。 |
source-map | 是 | 具有高质量 SourceMap 的生产构建的推荐选择。打包会生成.map映射文件 |
inline-source-map | 是 | 无ShourceMap文件,构建:最慢;重建:最慢。打包不会生成.map映射文件 |
none | 否 | 生产环境用 具有最高性能的生产构建的推荐选择。 好像这个不行呢,使用报错 |
环境变量
1 | "dev": "webpack server --config webpack.config.js --env development", |
webpack-merge合并webpack配置
webpack.config.js 入口配置
1
2
3
4
5
6
7
8
9
10
11
12const {merge} = require('webpack-merge');
const webpackComm = require('./webpack.config.comm');
const webpackDev = require("./webpack.config.dev");
const webpackProd = require('./webpack.config.production');
module.exports =(e)=> {
const mode = e.production?'production' : 'development';
if(mode === 'production'){
return merge(webpackComm,webpackProd,{mode})
}else{
return merge(webpackComm,webpackDev,{mode});
}
}webpack.config.comm.js
1
2
3
4
5
6
7
8
9
10
11
12
13const {resolve} = require('path');
module.exports = {
entry:{
app:'./app.js'
},
output:{
path:resolve(__dirname,'dist'),
filename:"js/[name].js",
clean:true
},
}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
24
25
26
27
28
29
30const {resolve} = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
},
{
test:/\.(jpe?g|png)$/,
type:'asset/resource',
generator:{
filename:'[name]-[contenthash][ext]'
}
}
]
},
devtool:'eval',
plugins:[
new MiniCssExtractPlugin({
filename:'[name].css'
}),
new HtmlWebpackPlugin({
title:'webpack 打包的html'
})
]
}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
30const {resolve} = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
},
{
test:/\.(jpe?g|png)$/,
type:'asset/resource',
generator:{
filename:'img/[name]-[contenthash][ext]'
}
}
]
},
devtool:'eval',
plugins:[
new MiniCssExtractPlugin({
filename:'css/[name].css'
}),
new HtmlWebpackPlugin({
title:'webpack 打包的html'
})
]
}以上配置通过webpack.config.js入口配置文件,使用webpack-merge配置合并开发/生产 与公共配置合并成最后配置。
此时在package.json中仅需要配置环境变量即可
1
2"build:prod": "webpack --config webpack.config.js --env production"
"build:dev": "webpack --config webpack.config.js --env development"
devserver
几个重要参数
compress 为true 启用GZIP压缩
http2 使用 spdy 提供 HTTP/2 服务 HTTP/2 带有自签名证书:
https 默认情况下,开发服务器将通过 HTTP 提供服务。可以选择使用 HTTPS 提供服务
devMiddleware:{
writeToDisk: true,
} npx webpack server时,将内存中打包的代码写入到实体文件夹中
headers 为所有响应添加 headers:
1
2
3
4
5devServer: {
headers: {
'X-Custom-Foo': 'bar',
},
},hot 启用 webpack 的 热模块替换 特性:
liveReload 默认情况下,当监听到文件变化时 dev-server 将会重新加载或刷新页面。
open 告诉 dev-server 在服务器已经启动后打开浏览器。设置其为 true 以打开你的默认浏览器。
proxy 设置接口代理 假定项目中请求了以下接口
1
2http://www.shaoyuhong.cm/api/hello
http://www.shaoyuhong.cm/axios/test最简单的一个代理 开发环境将请求地址为: http://www.shaoyuhong.cn/api/….
1
2
3
4
5devserver:{
proxy:{
'/api':"http://www.shaoyuhong.cn"
}
}路径重写 开发环境将请求地址为: http://www.shaoyuhong.cn/api2/….
1
2
3
4
5
6
7
8devserver:{
proxy:{
'/api':{
target:"http://www.shaoyuhong.cn",
pathRewrite: { '^/api': '/api2' },
}
}
}设置多个代理
开发环境将请求地址为:http://127.0.0.1:18002/interface/…. && http://127.0.0.1:18002/shao/……
1
2
3
4
5
6
7
8
9
10
11{
context:['/interface'],
target:'http://127.0.0.1:18002'
},
{
context:['/api'],
target:'http://127.0.0.1:18002',
pathRewrite:{
'^/api':'/shao'
}
}
默认情况下,将不接受在 HTTPS 上运行且证书无效的后端服务器。 如果需要secure:false,可以这样修改配置:
1
2
3
4
5
6
7
8
9
10
11module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'https://other-server.example.com',
secure: false,
},
},
},
};默认情况下,代理时会保留主机头的来源,可以将 changeOrigin 设置为 true 以覆盖此行为。 在某些情况下,例如使用 name-based virtual hosted sites,它很有用。
1
2
3
4
5
6
7
8
9
10
11module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
},
},
},
};参考链接:https://webpack.docschina.org/configuration/dev-server/#devserverproxy
插件
TerserWebpackPlugin
1 | npm install terser-webpack-plugin --save-dev |
该插件使用 terser 来压缩 JavaScript。
1 | const TerserPlugin = require("terser-webpack-plugin"); |
参考文档:https://webpack.docschina.org/plugins/terser-webpack-plugin/
HtmlWebpackPlugin
1 | npm install --save-dev html-webpack-plugin |
HtmlWebpackPlugin
简化了 HTML 文件的创建,以便为你的 webpack 包提供服务
1 | { |
生成多个html文件 ??
1 | const arr = ['shao','yu','hong']; |
内置变量
1 |
|
mini-css-extract-plugin
用于将style-loader生成的style标签样式,打包成css文件,使用link引入
外部扩展
防止将某些 包,如jQuery/Echarts…不打包在boundle中,而是使用script标签外部引入
例如,从 CDN 引入 jQuery,而不是把它打包:
index.html
1 | <script |
webpack.config.js
1 | module.exports = { |
这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:
1 | import $ from 'jquery'; //jquery来自于externals配置的属性名 |
优化
离线运行
渐进式网络应用程序(progressive web application - PWA),是一种可以提供类似于 native app(原生应用程序) 体验的 web app(网络应用程序)。PWA 可以用来做很多事。其中最重要的是,在**离线(offline)**时应用程序能够继续运行功能。这是通过使用名为 Service Workers 的 web 技术来实现的
参考链接:https://webpack.docschina.org/guides/progressive-web-application/
添加 Workbox
我们通过搭建一个拥有更多基础特性的 server 来测试下这种离线体验。这里使用 http-server package: 这一步其实可以不用做,添加workbox-webpack-pulgin后,使用webpack直接起服务效果也是相同的npm install http-server --save-dev
。还要修改 package.json
的 scripts
部分,来添加一个 start
script:
添加 workbox-webpack-plugin 插件,然后调整 webpack.config.js
文件:
1 | npm install workbox-webpack-plugin --save-dev |
webpack.config.js
1 | const path = require('path'); |
完成这些设置,再次执行 npm run build
,看下会发生什么:
1 | ... |
现在你可以看到,生成了两个额外的文件:service-worker.js
和名称冗长的 precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js
。service-worker.js
是 Service Worker 文件,precache-manifest.b5ca1c555e832d6fbf9462efd29d27eb.js
是 service-worker.js
引用的文件,所以它也可以运行。你本地生成的文件可能会有所不同;但是应该会有一个 service-worker.js
文件。
所以,值得高兴的是,我们现在已经创建出一个 Service Worker。接下来该做什么?
注册 Service Worker
接下来我们注册 Service Worker,使其出场并开始表演。通过添加以下注册代码来完成此操作:
index.js
1 | import _ from 'lodash'; |
再次运行 npm run build
来构建包含注册代码版本的应用程序。然后用 npm start
启动服务。访问 http://localhost:8080
并查看 console 控制台。在那里你应该看到:
1 | SW registered |
现在来进行测试。停止 server 并刷新页面。如果浏览器能够支持 Service Worker,应该可以看到你的应用程序还在正常运行。然而,server 已经停止 serve 整个 dist 文件夹,此刻是 Service Worker 在进行 serve。
Tree Shaking
生成环境 usedExports
usedExports 会将写的模块导入未使用的模块打包时丢弃
1
2
3
4mode:'production',
optimization: {
usedExports: true,
},如
1
2
3
4
5
6import {
sum,
cheng,
sinData
} from './until';
console.log(sum(100,200));打包后只会生成
1
(()=>{"use strict";console.log(300)})();
sideEffects 将文件标记为 side-effect-free(无副作用)
即,把某个文件标记为无副作用后,使用import导入的模块如果没有在代码中使用时,直接删除,包括CSS
pagage.json中添加sideEffects:false
1
2
3
4
5
6{
"name": "awesome npm module",
"version": "1.0.0",
"sideEffects": false, //false=>模块中任何文件无副作用,如果没有用到,可以随意删除,包括引入的CSS ;true=>有副作用,不可以随意删除
"sideEffects": ["./src/some-side-effectful-file.js","./style.less","*.css"] //这个文件有副作用,涉及到这几处文件不能删除
}sideEffects === false时
1
2
3
4
5
6
7import './style.less'
import {
sum,
cheng,
sinData
} from './until';
console.log(sum(100,200));打包后
1
(()=>{"use strict";console.log(300)})();
sideEffects === true时
1
(()=>{"use strict";var e,n,t,r,o,a,s,i,c,u,l,p,d,f,v={156:(e,n,t)=>{t.d(n,{Z:()=>i});var r=t(81),o=t.n(r),a=t(645),s=t.n(a)()(o());s.push([e.id,"ul,\nli {\n list-style-type: none;\n}\nul {\n display: flex;\n}\nul li {\n flex: 1;\n line-height: 2em;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n",""]);const i=s},645:e=>{e.exports=function(e){var n=[];return n.toString=function(){return this.map((function(n){var t="",r=void 0!==n[5];return n[4]&&(t+="@supports (".concat(n[4],") {")),n[2]&&(t+="@media ".concat(n[2]," {")),r&&(t+="@layer".concat(n[5].length>0?" ".concat(n[5]):""," {")),t+=e(n),r&&(t+="}"),n[2]&&(t+="}"),n[4]&&(t+="}"),t})).join("")},n.i=function(e,t,r,o,a){"string"==typeof e&&(e=[[null,e,void 0]]);var s={};if(r)for(var i=0;i<this.length;i++){var c=this[i][0];null!=c&&(s[c]=!0)}for(var u=0;u<e.length;u++){var l=[].concat(e[u]);r&&s[l[0]]||(void 0!==a&&(void 0===l[5]||(l[1]="@layer".concat(l[5].length>0?" ".concat(l[5]):""," {").concat(l[1],"}")),l[5]=a),t&&(l[2]?(l[1]="@media ".concat(l[2]," {").concat(l[1],"}"),l[2]=t):l[2]=t),o&&(l[4]?(l[1]="@supports (".concat(l[4],") {").concat(l[1],"}"),l[4]=o):l[4]="".concat(o)),n.push(l))}},n}},81:e=>{e.exports=function(e){return e[1]}},379:e=>{var n=[];function t(e){for(var t=-1,r=0;r<n.length;r++)if(n[r].identifier===e){t=r;break}return t}function r(e,r){for(var a={},s=[],i=0;i<e.length;i++){var c=e[i],u=r.base?c[0]+r.base:c[0],l=a[u]||0,p="".concat(u," ").concat(l);a[u]=l+1;var d=t(p),f={css:c[1],media:c[2],sourceMap:c[3],supports:c[4],layer:c[5]};if(-1!==d)n[d].references++,n[d].updater(f);else{var v=o(f,r);r.byIndex=i,n.splice(i,0,{identifier:p,updater:v,references:1})}s.push(p)}return s}function o(e,n){var t=n.domAPI(n);return t.update(e),function(n){if(n){if(n.css===e.css&&n.media===e.media&&n.sourceMap===e.sourceMap&&n.supports===e.supports&&n.layer===e.layer)return;t.update(e=n)}else t.remove()}}e.exports=function(e,o){var a=r(e=e||[],o=o||{});return function(e){e=e||[];for(var s=0;s<a.length;s++){var i=t(a[s]);n[i].references--}for(var c=r(e,o),u=0;u<a.length;u++){var l=t(a[u]);0===n[l].references&&(n[l].updater(),n.splice(l,1))}a=c}}},569:e=>{var n={};e.exports=function(e,t){var r=function(e){if(void 0===n[e]){var t=document.querySelector(e);if(window.HTMLIFrameElement&&t instanceof window.HTMLIFrameElement)try{t=t.contentDocument.head}catch(e){t=null}n[e]=t}return n[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(t)}},216:e=>{e.exports=function(e){var n=document.createElement("style");return e.setAttributes(n,e.attributes),e.insert(n,e.options),n}},565:(e,n,t)=>{e.exports=function(e){var n=t.nc;n&&e.setAttribute("nonce",n)}},795:e=>{e.exports=function(e){var n=e.insertStyleElement(e);return{update:function(t){!function(e,n,t){var r="";t.supports&&(r+="@supports (".concat(t.supports,") {")),t.media&&(r+="@media ".concat(t.media," {"));var o=void 0!==t.layer;o&&(r+="@layer".concat(t.layer.length>0?" ".concat(t.layer):""," {")),r+=t.css,o&&(r+="}"),t.media&&(r+="}"),t.supports&&(r+="}");var a=t.sourceMap;a&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),n.styleTagTransform(r,e,n.options)}(n,e,t)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(n)}}}},589:e=>{e.exports=function(e,n){if(n.styleSheet)n.styleSheet.cssText=e;else{for(;n.firstChild;)n.removeChild(n.firstChild);n.appendChild(document.createTextNode(e))}}}},m={};function h(e){var n=m[e];if(void 0!==n)return n.exports;var t=m[e]={id:e,exports:{}};return v[e](t,t.exports,h),t.exports}h.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return h.d(n,{a:n}),n},h.d=(e,n)=>{for(var t in n)h.o(n,t)&&!h.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},h.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),h.nc=void 0,e=h(379),n=h.n(e),t=h(795),r=h.n(t),o=h(569),a=h.n(o),s=h(565),i=h.n(s),c=h(216),u=h.n(c),l=h(589),p=h.n(l),d=h(156),(f={}).styleTagTransform=p(),f.setAttributes=i(),f.insert=a().bind(null,"head"),f.domAPI=r(),f.insertStyleElement=u(),n()(d.Z,f),d.Z&&d.Z.locals&&d.Z.locals,console.log(300)})();
Shimming 预置依赖
参考链接:https://webpack.docschina.org/guides/shimming/#granular-shimming
Shimming 预置全局变量
通过webpack new webpack.ProvidePlugin
暴露出全局变量,使得入口内部的js无论层级 都不需要再引入该模块,可以直接使用
1 | const path = require('path'); |
如 a.js/b.js/c.js都可以使用使用$,无需再引入jquery
细粒度 Shimming
使用webpack后,this
不再指向window
对象,代码中如果使用this对象访问window时,无法获取,this为undefined
为解决这个问题
你可以通过使用 imports-loader
覆盖 this
指向:
安装 imports-loader
1
npm i imports-loader -D
修改modules
1
2
3
4
5
6
7
8module: {
+ rules: [
+ {
+ test: require.resolve('./src/index.js'),
+ use: 'imports-loader?wrapper=window',
+ },
+ ],
+ },注意一点,使用imports-loader去修改this指针后,该js文件不能有其它类型的文件,如less/css等,否则将无法处理该文件
加载 Polyfills
安装
1 | npm install --save-dev @babel/preset-env |
webpack添加到module
1 | { |
全局 Exports
作用
用于非npm包时三方插件,这个插件没有使用es6或者comm.js语法导出,可以使用webpack导出并使用es6 comm.js导入的形式使用,请看下面的例子
假定我下载了一个三方插件,这个插件是普通的js文件,无export 或者 module.exports
1 | //ani.js |
问题来了,如何在我们的模块化js中 正常使用import /require导出fileName
copyApi
Ani
这些函数、变量?
答案:**使用 exports-loader可以解决这个问题** https://webpack.docschina.org/loaders/exports-loader/
在webpack中配置
1 | { |
现在我们在某个js文件中,可以正常导入使用
1 | const methods = require('./ani'); |
Web Workers
客户端原来和服务端可以相互通信,**原来以为,只能服务端 主动向客户端推送消息,并不能接收客户端数据**
客户端
1 | const worker = new Worker(new URL('./server.js', import.meta.url)); |
服务端
1 | var i=0; |
web wokrder如果在webpack使用时,使用方式请参考:https://webpack.docschina.org/guides/web-workers/
打包图片资源
- webpack5版本像url-loader,file-loder都是废弃不会直接使用的。我整了半天,虽然打包了图片,但是却打包了两次,并且无法显示图片了,
如果想要使用这些废弃的旧功能,加上type: javascript/auto
esModule: false
, 打包图片时需要关闭ES modulesoutputPath:'static/img',
配置将资源文件输出的位置
1 | module:{ |
在webpack5中打包资源文件的修改
在 webpack 5 之前,通常使用:
raw-loader
将文件导入为字符串url-loader
将文件作为 data URI 内联到 bundle 中file-loader
将文件发送到输出目录
资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
asset/resource
发送一个单独的文件并导出 URL。之前通过使用file-loader
实现。asset/inline
导出一个资源的 data URI。之前通过使用url-loader
实现。asset/source
导出资源的源代码。之前通过使用raw-loader
实现。asset
在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用url-loader
,并且配置资源体积限制实现。url-loader与fileloader自动选择Rule.parser.dataUrlCondition:{maxSize:4*1024} 可以配置文件大小 的选择方式
当在 webpack 5 中使用旧的 assets loader(如 file-loader
/url-loader
/raw-loader
等)和 asset 模块时,你可能想停止当前 asset 模块的处理,并再次启动处理,这可能会导致 asset 重复,你可以通过将 asset 模块的类型设置为 'javascript/auto'
来解决。
generator:filename可以支持一个路径,将文件分类打包到不同的文件夹中
exclude 除开某个条件外的所有情况,都按此方法处理
1 | { |
原文参考:https://webpack.docschina.org/guides/asset-modules/
output.assetModuleFilename:’shao/[hash] [ext]’ 可以将静态资源统一设置一个路径,当有generator中filename指定的路径时,优先于generator
TypeScript
参考链接:https://webpack.docschina.org/guides/typescript/
使用typescript时,如果安装其它插件,如jquery/react,需要同时安装插件的类型申明文件,可点击链接自行安装
插件类型安装地址:https://www.typescriptlang.org/dt/search?search=
使用npx tsc --init
可以快速生成typescript的配置文件tsconfig.json
自定义插件
要在 Webpack 插件中实现替换打包文件中的 ‘A’ 为 ‘Z’,你可以使用 compiler.hooks.emit
钩子来修改生成的文件。
以下是一个示例,展示了如何使用自定义插件来替换打包文件中的 ‘A’ 为 ‘Z’:
1 | javascript复制class ReplaceFilePlugin { |
在这个示例中,我们定义了一个名为 ReplaceFilePlugin
的自定义插件。在插件的 apply
方法中,我们注册了 compiler.hooks.emit
钩子,并在钩子函数中进行文件替换的逻辑。
我们遍历 compilation.assets
对象中的每个文件,判断文件名是否以 .js
结尾。如果是 JavaScript 文件,我们获取文件的源代码,并使用正则表达式将所有的 ‘A’ 替换为 ‘Z’。然后,我们将替换后的源代码重新赋值给 compilation.assets[filename]
,并更新文件的大小。
这样,在最终的打包结果中,所有 JavaScript 文件中的 ‘A’ 将被替换为 ‘Z’。
要使用这个自定义插件,你需要在 Webpack 配置文件中引入并实例化它:
1 | javascript复制const ReplaceFilePlugin = require('./ReplaceFilePlugin'); |
webpack plugins执行顺序
Webpack 插件的钩子函数执行顺序是按照一定的生命周期顺序来执行的。以下是一些常见的 Webpack 插件钩子函数及其执行顺序的说明:
beforeRun
:在 Webpack 开始运行之前触发的钩子函数。run
:Webpack 开始运行时触发的钩子函数。beforeCompile
:在编译之前触发的钩子函数。compile
:Webpack 开始编译时触发的钩子函数。compilation
:每次成功完成一次编译时触发的钩子函数。make
:在创建编译对象之前触发的钩子函数。afterCompile
:在编译完成之后触发的钩子函数。emit
:在生成资源到输出目录之前触发的钩子函数。afterEmit
:在生成资源到输出目录之后触发的钩子函数。done
:Webpack 完成构建后触发的钩子函数。
这些钩子函数按照从开始到结束的顺序依次执行,每个钩子函数都有特定的用途和时机。你可以根据需要选择合适的钩子函数来执行自定义的操作。
需要注意的是,有些钩子函数是同步执行的,而有些是异步执行的。对于异步执行的钩子函数,你需要在回调函数中显式地调用回调函数来通知 Webpack 继续执行。
在编写插件时,你可以根据具体的需求选择合适的钩子函数,并按照它们的执行顺序来编写相应的逻辑。
plugins tap与tapSync区别
在 Webpack 的自定义插件中,tapAsync
和 tap
是两个不同的钩子函数注册方法,它们在使用方式和功能上有一些区别。
tapAsync
:tapAsync
方法用于注册异步的钩子函数。这意味着你可以在回调函数中执行异步操作,并在操作完成后调用回调函数来通知 Webpack 继续执行。回调函数接受一个参数作为完成操作的标志,通常命名为callback
。你需要在回调函数中调用callback
来告诉 Webpack 异步操作已完成。
1 | javascript复制compiler.hooks.someHook.tapAsync('MyPlugin', (param1, param2, callback) => { |
tap
:tap
方法用于注册同步的钩子函数。这意味着你可以在回调函数中执行同步操作,而不需要显式地调用回调函数。回调函数接受参数,这些参数是由 Webpack 传递给钩子函数的。
1 | javascript复制compiler.hooks.someHook.tap('MyPlugin', (param1, param2) => { |
总结来说,tapAsync
用于注册异步的钩子函数,需要显式地调用回调函数来通知 Webpack 异步操作已完成。而 tap
用于注册同步的钩子函数,不需要显式地调用回调函数。
在使用这两个方法时,你需要根据具体的需求和钩子函数的特性来选择合适的方法。
vite实现提出项目关键字
1 | import { defineConfig } from 'vite' |
其它事项
html-loader与html-webpack-plugin 有变量解析时,如
1
<title><%= htmlWebpackPlugin.options.title %></title>
当配置了module:{loader:’html-loader’ }存在冲突,标题不能解析出来
ProvidePlugin 自动加载模块,而不必到处 import 或 require 。
1
2
3
4new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
});DefinePlugin DefinePlugin 允许创建一个在编译时可以配置的全局常量。这可能会对开发模式和生产模式的构建允许不同的行为非常有用
1
2
3
4
5
6
7
8new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify('5fa3b9'),
BROWSER_SUPPORTS_HTML5: true,
TWO: '1+1',
'typeof window': JSON.stringify('object'),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
});值得注意的是,这里只能传【数字、字符串】。Array/object/booble/string需要使用json.stringify,属性名可以不用大写
webpack至此完结
2022/5/25
- 本文标题:webpack学习计划来啦
- 本文作者:邵预鸿
- 创建时间:2022-01-10 18:11:09
- 本文链接:/images/logo.jpg2022/01/10/webpack学习计划来啦/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!