在咱们平时的开发中,会常用到webpack,但不少时候咱们都不作任何配置(webpack4)也能够进行开发,可是默认的配置真的够咱们使用了吗?因此本文将带你开启webpack的大门。javascript
学习webpack前先让咱们一块儿学习下必要的辅助概念css
在此以前咱们有必要了解下webpack中会使用到的NodeJS路径知识:NodeJS路径知识html
Entry 用来指定 webpack 的打包⼊口html5
单⼊⼝:entry 是⼀个字符串java
module.exports = {
entry: './src/index.js'
};
复制代码
多⼊⼝:entry 是⼀个对象node
module.exports = {
entry: {
index: './src/index.js',
manager: './src/manager.js'
}
};
复制代码
Output ⽤来告诉 webpack 如何将编译后的⽂件输出到磁盘的指定路径react
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js’,
path: __dirname + '/dist'
}
};
复制代码
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
};
复制代码
经过[name]占位符确保⽂件名称的惟⼀webpack
自己是一个函数,接受源文件做为参数,返回转换的结果。ios
babel-loader, 将es6+语法转换为es3/es5语法
css-loader,
style-loader,
scss-loader,
less-loader,
postcss-loader,
file-loader, 进行图片字体等资源的打包
ts-loader, 将ts转换为js
raw-loader 将文件以字符串形式导入
...
复制代码
const path = require('path');
module.exports = {
output: {
filename: 'bundle.js'
},
module: {
rules: [
{ test: /\.js$/, use: 'babel-loader' }
]
}
};
复制代码
test 指定匹配规则css3
use 指定使⽤的 loader 名称
插件⽤于 bundle ⽂件的优化,资源管理和环境变量注⼊ 做⽤于整个构建过程
CleanWebpackPlugin 清理构建目录
MiniCssExtractPlugin 将css从bundle文件里提取为一个独立的css文件
htmlWebpackPlugin 建立html去承载输出的bundle文件
UglifyWebpackPlgin 压缩js 去除console等指定语句
...
复制代码
const path = require('path');
module.exports = {
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlWebpackPlugin({template:'./src/index.html'})
]
};
复制代码
全部的插件都应放到plugins数组里
在此以前咱们先安装下必须依赖:
npm install webpack webpack-cli -D
复制代码
安装所需依赖 npm i @babel/core @babel/preset-env babel-loader -D
配置以下:
babel的配置⽂件是:.babelrc[项目根目录下新建]
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
]
};
复制代码
babel的配置⽂件是:.babelrc[项目根目录下新建]
{
"presets": [
"@babel/preset-env" //能够根据配置的目标浏览器或者运行环境来自动将ES2015+的代码转换为es5。
]
}
复制代码
安装所需依赖
npm i @babel/preset-react -D
配置以下:
babel的配置⽂件是:.babelrc[项目根目录下新建]
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": []
}
复制代码
npm install style-loader css-loader less-loader -D
复制代码
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
]
},
复制代码
css-loader ⽤于加载 .css ⽂件,而且转换成 commonjs 对象
style-loader 将样式经过 <style>
标签插⼊到 head 中
style-loader配置:
options: {
insertAt: 'top', // 样式插入到 <head>
singleton: true, //将全部的style标签合并成一个
}
复制代码
less-loader 将less语法转换为css语法
注意: loader的执行顺序的从下到上,从右到左
npm install url-loader file-loader -D
复制代码
module: {
rules: [
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: 'file-loader'
}
]
},
复制代码
file-loader ⽤于处理字体⽂件
url-loader 能够用来处理图⽚和字体 能够设置limit将较⼩资源⾃动 base64
url-loader中用到了file-loader
⽂件监听是在发现源码发⽣变化时,⾃动从新构建出新的输出⽂件。
webpack 开启监听模式,有两种⽅式:
·启动 webpack 命令时,带上 --watch 参数 [推荐]
·在配置 webpack.config.js 中设置 watch: true
在package.json中配置
{
"name": "hello-webpack",
"main": "index.js",
"scripts": {
"watch": "webpack --watch",
"build": "webpack --config webpack.prod.js",
},
}
复制代码
npm install webpack-dev-server -D
复制代码
package.json中的scripts对象下配置:
{
"scripts": {
"dev": "webpack-dev-server --open"
},
}
复制代码
--open表明自动打开浏览器
webpack-dev-server 不刷新浏览器 不输出⽂件,⽽是放在内存中
使⽤ HotModuleReplacementPlugin插件(webpack内置插件)可使浏览器自动刷新
webpack.config.js中配置:
const webpack = require('webpack');
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
devServer:{
hot: true,
contentBase:'./dist'
}
复制代码
Webpack Compile: 将 JS 编译成 Bundle
HMR Server: 将热更新的⽂件输出给 HMR Rumtime
Bundle server: 提供⽂件在浏览器的访问 (好比localhost:8080/Bundle.js)
HMR Rumtime: 在开发阶段的打包阶段会被注⼊到浏览器端的bundle.jjs中,浏览器端的bundle.jjs会和浏览器创建一个链接,一般是一个websocket,这样就能够更新文件的变化,当收到文件的一些变化消息时会自动更新文件
bundle.js: 构建输出的⽂件
⽂件哈希值就是打包后输出的⽂件名的后缀
Hash:和整个项⽬的构建相关,只要项⽬⽂件有修改,整个项⽬构建的 hash 值就会更改
Chunkhash:和 webpack 打包的 chunk 有关,不一样的 entry 会⽣成不一样的 chunkhash 值
Contenthash:根据⽂件内容来定义 hash ,⽂件内容不变,则 contenthash 不变
设置 output 的 filename,使⽤ [chunkhash]
output: {
filename: '[name][chunkhash:8].js',
path: __dirname + '/dist'
}
复制代码
注意: chunkhash没法和热更新一块儿使用
设置 MiniCssExtractPlugin 的 filename,
使⽤ [contenthash]
npm i install mini-css-extract-plugin -D
复制代码
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
plugins: [
new MiniCssExtractPlugin({
filename: `[name][contenthash:8].css`
});
]
复制代码
若是想把css提取出来,那么style-loader就不能用了,由于两个是互斥的,因此咱们能够这样写:
module: {
rules: [
{
test: /\.css$/,
use: [
- 'style-loader',
+ MiniCssExtractPlugin.loader
'css-loader'
]
},
{
test: /\.less$/,
use: [
- 'style-loader',
+ MiniCssExtractPlugin.loader
'css-loader',
'less-loader'
]
},
]
},
复制代码
module: {
rules: [
{
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'file-loader’,
options: {
name: 'img/[name][hash:8].[ext] '
}
}]
}
]
复制代码
[ext] 资源名后缀 [name] 文件名称 [path] 文件的相对路径 [folder] 文件所在的文件夹 [contenthash] 文件的内容hash 默认md5生成 [hash] 文件内容的hash 默认md5生成
HTML 压缩
CSS 压缩
JS 压缩
npm install uglifyjs-webpack-plugin -D
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
plugins: [
new UglifyJsPlugin()
]
复制代码
npm install optimize-css-assets-webpack-plugin cssnano -D
复制代码
使⽤ optimize-css-assets-webpack-plugin, 同时使⽤ cssnano[预处理器]
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
plugins: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano’)
})
]
复制代码
npm install html-webpack-plugin -D
复制代码
使用html-webpack-plugin,设置压缩参数
webpack.config.js中
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/dist/index.html’),
filename: 'index.html’,
chunks: ['index’],
inject: true,
minify: {
html5: true,
collapseWhitespace: true, //去除空格
preserveLineBreaks: false, //去除换行
minifyCSS: true,
minifyJS: true,
removeComments: false //去除注释
}
})
]
复制代码
避免构建前每次都须要⼿动删除 dist
使⽤ clean-webpack-plugin
默认会删除 output 指定的输出⽬录
npm install clean-webpack-plugin -D
const CleanWebpackPlugin = require('clean-webpack-plugin');
plugins: [
new CleanWebpackPlugin(),
]
复制代码
IE: Trident(-ms) 火狐: Geko(-moz) 谷歌: Webkit(-webkit) 欧鹏:Presto(-o)
npm install postcss-loader autoprefixer -D
复制代码
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
browsers: ['last 2 version', '>1%', 'ios 7']
})
]
}
},
]
},
]
},
复制代码
rem 是什么?
W3C 对 rem 的定义: font-size of the root element
rem 和 px 的对⽐:
rem 是相对单位
px 是绝对单位
⻚⾯渲染时计算根元素的 font-size 值,可使⽤⼿淘的lib-flexible库
npm install px2rem-loader -D
npm i lib-flexible raw-loader@0.5.1 -S
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
browsers: ['last 2 version', '>1%', 'ios 7']
})
]
}
},
{
loader: 'px2rem-loader',
options: {
remUnit: 75,
remPrecision: 8 //转换好rem的小数点位数
}
}
]
}
]
}
复制代码
index.html中使用raw-loader内联lib-flexible
<script> ${require('raw-loader!babel-loader!../node_modules/lib-flexible')} </script>
复制代码
<script> ${require(' raw-loader!babel-loader!. /meta.html')} </script>
复制代码
每⼀次⻚⾯跳转的时候,后台服务器都会给返回⼀个新的 html ⽂档, 这种类型的⽹站也就是多⻚⽹站,也叫作多⻚应⽤。
多⻚⾯打包通⽤⽅案: 动态获取 entry 并设置 html-webpack-plugin
利用glob
库
webpack.config.js中编写以下代码:
npm install glob -D
const glob = require('glob');
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
const setMPA = () => {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));
Object.keys(entryFiles)
.map((index) => {
const entryFile = entryFiles[index];
const match = entryFile.match(/src\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = entryFile;
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
inlineSource: '.css$',
template: path.join(__dirname, `src/${pageName}/index.html`),
filename: `${pageName}.html`,
chunks: ['vendors', pageName],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
})
);
});
return {
entry,
htmlWebpackPlugins
}
}
const { entry, htmlWebpackPlugins } = setMPA();
module.exports = {
entry: entry,
plugins: [].concat(htmlWebpackPlugins)
}
复制代码
能够经过devtool:'cheap-source-map'配置
思路:将 react、react-dom,axios,element-ui 基础包经过 cdn 引⼊,不打⼊ bundle 中
npm install html-webpack-externals-plugin -D
使⽤ html-webpackexternals-plugin
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
plugins:[
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: 'cdn.com/react.min.js',
global: 'React',
},
{
module: 'axios',
entry: 'cdn.com/axios.min.js',
global: 'Axios',
},
]
}),
]
复制代码
SplitChunksPlugin是Webpack4 内置的,替代webpack3的CommonsChunkPlugin插件
async 异步引⼊的库进⾏分离(默认)
initial 同步引⼊的库进⾏分离
all 全部引⼊的库进⾏分离(推荐)
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,//抽离的公共包最小的大小
maxSize: 0, //抽离的公共包最大的大小
minChunks: 1, //一段代码多处都使用的次数 若是大于这里的次数就抽离成公共的文件
maxAsyncRequests: 5,
maxInitialRequests: 3,//浏览器同时请求的异步js的数量
name: true,
cacheGroups: {
vendors: {
test: /(axios|react)/,
priority: -10,
minChunks: 1
}
}
}
}
复制代码
概念:1 个模块可能有多个⽅法,只要其中的某个⽅法使⽤到了,则整个⽂件都会被打到bundle ⾥⾯去,tree shaking 就是只把⽤到的⽅法打⼊ bundle ,没⽤到的⽅法会在uglify 阶段被擦除掉。
使⽤:webpack4 默认⽀持,在 .babelrc ⾥设置 modules: false 便可 要求:必须是 ES6 的语法,CommonJS 的⽅式不⽀持.
production mode的状况下默认开启
treeShaking的状况:
代码执⾏的结果不会被⽤到
代码不会被执⾏,不可到达
代码只会影响死变量(只写不读)
复制代码
Tree-shaking 原理 利⽤ ES6 模块的特色:
只能做为模块顶层的语句出现
import 的模块名只能是字符串常量
import binding 是 immutable的
代码擦除: uglify 阶段删除⽆⽤代码
若是代码中有反作用则tree-shaking失效
能够在package.json中配置sideEffect:[] 好比babel-polyfill
⼤量做⽤域包裹代码,致使体积增⼤(模块越多越明显)
运⾏代码时建立的函数做⽤域变多,内存开销变⼤
结论:
被 webpack 转换后的模块会带上⼀层包裹
import 会被转换成 __webpack_require
分析: 打包出来的是⼀个 IIFE (匿名闭包)
modules 是⼀个数组,每⼀项是⼀个模块初始化函数
__webpack_require ⽤来加载模块,返回 module.exports
原理:将全部模块的代码按照引⽤顺序放在⼀个函数做⽤域⾥,而后适当的重命名⼀些变量以防⽌变量名冲突
必须是 ES6 语法,CJS 不⽀持
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
复制代码
webpack 有⼀个功能就是将你的代码库分割成chunks(语块),当代码运⾏到须要它们的时候再进⾏加载。
CommonJS:require.ensure
ES6:动态 import(⽬前尚未原⽣⽀持,须要 babel 转换)
安装 babel 插件 ES6:动态 import(⽬前尚未原⽣⽀持,须要 babel 转换)
在.babelrc中配置:
npm install @babel/plugin-syntax-dynamic-import --save-dev
{
"plugins": ["@babel/plugin-syntax-dynamic-import"],
}
复制代码
代码中的使用:
loadComponent() {
import('./text.js').then((Text) => {
this.setState({
Text: Text.default
});
});
}
复制代码
这样的话text.js在打包时就会被自动拆分为一个单独的文件,当咱们调用这个方法时才进行加载,也算是一个优化手段
webpack 除了能够⽤来打包应⽤,也能够⽤来打包 js 库
实现⼀个加法库的打包
须要打包压缩版和⾮压缩版本
⽀持 AMD/CJS/ESM 模块引⼊
//src下index.js
export default function add(a, b) {
return a + b;
}
复制代码
只对.min 压缩可使用TerserPlugin插件进行匹配
npm install terser-webpack-plugin -D
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: {
'large-number': './src/index.js',
'large-number.min': './src/index.js'
},
output: {
filename: '[name].js',
library: 'largeNumber',
libraryTarget: 'umd',
libraryExport: 'default'
},
mode: 'none',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
include: /\.min\.js$/,
})
]
}
}
//index.js中
if (process.env.NODE_ENV === 'production') {
module.exports = require('./dist/large-number.min.js');
} else {
module.exports = require('./dist/large-number.js');
}
复制代码
package.json 的 main 字段为 index.js
而后webpack打包就能够了
思路:
服务端 使⽤ react-dom/server 的 renderToString ⽅法将 React 组件渲染成字符串,服务端路由返回对应的模板
客户端
打包出针对服务端的组件
<!--search.html-->
<body>
<div id="root"><!--HTML_PLACEHOLDER--></div>
</body>
复制代码
这里使用注释进行占位
const fs = require('fs');
const path = require('path');
const express = require('express');
const { renderToString } = require('react-dom/server');
const SSR = require('../dist/search-server');
const template = fs.readFileSync(path.join(__dirname, 'search.html'), 'utf-8');
const server = (port) => {
const app = express();
app.use(express.static('dist'));
app.get('/search', (req, res) => {
const html = renderMarkup(renderToString(SSR));
res.status(200).send(html);
});
app.listen(port, () => {
console.log('Server is running on port:' + port);
});
};
server(process.env.PORT || 3000);
const renderMarkup = (str) => {
return template.replace('<!--HTML_PLACEHOLDER-->', str)
}
复制代码
使⽤ friendly-errors-webpack-plugin
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
plugins: [
new FriendlyErrorsWebpackPlugin()
],
stats: 'errors-only'
复制代码
plugins:[
new FriendlyErrorsWebpackPlugin(),
function() {
this.hooks.done.tap('done', (stats) => {
if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') == -1)
{
console.log('错误上报');
process.exit(1);
}
})
}
]
复制代码
compiler 在每次构建结束后会触发 done 这 个 hook
webpack4中是this.hooks.done.tap webpack3中是this.plugin
0 表示成功完成,回调函数中,err 为 null
⾮ 0 表示执⾏失败,回调函数中,err 不为 null,err.code 就是传给 exit 的数字
升级补丁版本号:npm version patch //通常是修改了bug
升级小版本号:npm version minor //通常是发布了feture
升级大版本号:npm version major //通常是重大更新
复制代码
npm install webpack-bundle-analyzer -D
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins:[
new BundleAnalyzerPlugin(),
]
复制代码
构建完成后会在 8888 端口展现大小
通常推荐使用高版本的node和webpack,由于他们内部本身作了优化
V8 带来的优化(for of 替代 forEach、Map 和 Set 替代 Object、includes 替代 indexOf)
默认使用更快的 md4 hash 算法
webpack AST 能够直接从 loader 传递给 AST,减小解析时间
使用字符串方法替代正则表达式
npm install cache-loader thread-loader -D
复制代码
使用 thread-loader 解析资源
原理:每次 webpack 解析一个模块,thread-loader 会将它及它的依赖分配给 worker 线程
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 3
}
},
'cache-loader',
'babel-loader',
]
},
]
}
复制代码
方式一:使用 parallel-uglify-plugin 插件
plugins:[
new ParallelUglifyPlugin({
uglifyJS:{
output:{
beautify:false,
comments:false
},
compress:{
warning:false,
drop_console:true,
collapse_vars:true,
reduce_vars:true
}
}
})
]
复制代码
方式二:uglifyjs-webpack-plugin 开启 parallel 参数
plugins:[
new UglifyJsPlugin({
uglifyOptions:{
warning:false
},
parallel:true
})
]
复制代码
方法三:terser-webpack-plugin 开启 parallel 参数
optimization:{
minimizer:[
new TerserPlugin({
parallel:4
})
]
}
复制代码
目的:尽量的少构建模块
好比 babel-loader 不解析 node_modules
rules: [
{
test: /\.js$/,
exclude: 'node_modules',
use: [
'babel-loader',
]
}
]
复制代码
优化 resolve.extensions 配置
合理使用 alias
resolve: {
alias: {
'components': path.resolve(__dirname, './src/components'),
'util': path.resolve(__dirname, './src/util'),
},
extensions: ['.js']
}
复制代码
使用:配置 image-webpack-loader
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8].[ext]'
}
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false,
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 75
}
}
}
复制代码
PurifyCSS: 遍历代码,识别已经用到的 CSS class 这个须要和 mini-css-extract-plugin 配合使用
也就是说先提取为css文件而后再使用PurifyCSS
npm install purgecss-webpack-plugin
const PurgecssPlugin = require('purgecss-webpack-plugin');
plugins:[
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
}),
new PurgecssPlugin({
paths: glob.sync(`${path.join(__dirname, 'src')}/**/*`, { nodir: true }),
})
]
复制代码
咱们可使用动态 Polyfill -> Polyfill Service
原理:识别 User Agent,下发不一样的 Polyfill
如何使用动态 Polyfill service
polyfill.io 官方提供的服务:
Scope Hoisting
Tree-shaking
公共资源分离
图片压缩
动态 Polyfill
//raw-loader.js
module.exports = function(source) {
const json = JSON.stringify(source)
.replace('foo', '')
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
return `export default ${json}`;
}
复制代码
咱们这个loader是把指定文件中的foo字符替换为空的 使用loader-runner测试loader是否正常工做:
npm install loader-runner -D
loader-runner用法具体能够去github查看
const { runLoaders } = require('loader-runner');
const fs = require('fs');
const path = require('path');
runLoaders({
resource: path.join(__dirname, './src/demo.txt'),//资源路径
loaders: [
{
loader: path.join(__dirname, './src/raw-loader.js'),//指定loader路径
}
],
context: {
minimize:true
},
readResource: fs.readFile.bind(fs)
}, (err, result) => {
err ? console.log(err) : console.log(result);
});
复制代码
npm install loader-utils -D
复制代码
经过 loader-utils 的 getOptions 方法获取
const loaderUtils = require("loader-utils");
module.exports = function(content) {
const { name } = loaderUtils.getOptions(this);
};
复制代码
loader 内直接经过 throw 抛出,经过 this.callback 传递错误
this.callback(
err: Error | null, content: string | Buffer, sourceMap?: SourceMap, meta?: any
);
复制代码
经过 this.async 来返回一个异步函数
第一个参数是 Error,第二个参数是处理的结果
module.exports = function(input) {
const callback = this.async();
this.cacheable(false)
// No callback -> return synchronous results
// if (callback) { ... }
callback(null, input + input);
};
复制代码
this.async()第一个参数也是err对象,第二个参数是数据
webpack 中默认开启 loader 缓存
可使用 this.cacheable(false) 关掉缓存
缓存条件: loader 的结果在相同的输入下有肯定的输出
有依赖的 loader 没法使用缓存
经过 this.emitFile 进行文件写入
const loaderUtils = require("loader-utils");
module.exports = function(content) {
const url = loaderUtils.interpolateName(this, "[hash].[ext]", {
content});
this.emitFile(url, content);
const path = `__webpack_public_path__ + ${JSON.stringify(url)};`;
return `export default ${path}`;
};
复制代码
interpolateName方法是用于替换占位符,__webpack_public_path__是webpack的全局变量
插件没有像 loader 那样的独立运行环境, 只能在 webpack 里面运行
const path = require('path');
const MyPlugin = require('./plugins/myPlugin');//插件开发阶段的路径
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
},
mode: 'production',
plugins: [
new MyPlugin({
name: 'myname'
})
]
}
复制代码
module.exports = class MyPlugin { //MyPlugin是插件名
constructor(options){
this.options = options
}
apply(compiler){ //必须是apply
console.log('个人插件执行了');
console.log('个人插件配置项',this.options)
}
}
复制代码
参数校验阶段能够直接 throw 的方式抛出
throw new Error(“ Error Message”)
复制代码
若是已经进入hooks逻辑,那么能够经过 compilation 对象的 warnings 和 errors 接收
compilation.warnings.push("warning");
compilation.errors.push("error");
复制代码
文件生成阶段webpack会调用emit这个hooks,因此咱们能够监听emit阶段进行操做
文件写入须要使用 [webpack-sources]((www.npmjs.com/package/web…)
const { RawSource } = require("webpack-sources");
module.exports = class DemoPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
const { name } = this.options;
compiler.plugin("emit", (compilation, cb) => {
compilation.assets[name] = new RawSource("demo");//demo为文件内容,name为文件的名称
cb();
});
}
};
复制代码
相信本文应该已经涵盖了webpack最常使用的点以及如何进行优化,感兴趣的小伙伴能够在文章下方进行交流哦