InlineChunkWebpackPlugin:
webpack 打包生成的 runtime 文件太小了,额外发送请求性能不好,所以需要将其内联到 js 中,从而减少请求数量)——提升速度 runtime保存依赖和hash
嵌入到html中需要使用html-webpack-plugin插件
- html-webpack-plugin 输出 index.html 前将内联 runtime 注入进去
- 删除多余的 runtime 文件
首先需要在配置文件中进行打包输出runtime文件
optimization:{
splitChunks:{//代码分割
chunks:'all'
},
runtimeChunk:{
name:entrypoint => `runtime~${entrypoint.name}.js`,
}
},
根据这个配置
下载依赖
npm i safe-require -D
实现效果
const HtmlWebpackPlugin = require("safe-require")("html-webpack-plugin");
class InlineChunkWebpackPlugin {
constructor(tests) {
this.tests = tests;
}
apply(compiler) {
compiler.hooks.compilation.tap("InlineChunkWebpackPlugin", (compilation) => {
// 1. 获取html-webpack-plugin的hooks
const hooks = HtmlWebpackPlugin.getHooks(compilation);
// 2. 注册 html-webpack-plugin的hooks -> alterAssetTagGroups
hooks.alterAssetTagGroups.tap("InlineChunkWebpackPlugin", (assets) => {
//3. 从里面将script的runtime文件,变成inline script
/*
assets.headTags: [
{
tagName: 'script',
voidTag: false,
meta: { plugin: 'html-webpack-plugin' },
attributes: { defer: true, type: undefined, src: 'js/runtime~main.js.js' }
},
*/
/*修改成为
assets.headTags: [
{
tagName: 'script',
closeTag: true,
meta: { plugin: 'html-webpack-plugin' },
innnerHTML:runtime的内容
},
*/
//对里面的内容处理使用使用公共方法为了复用
assets.headTags = this.getInlineChunk(assets.headTags, compilation.assets);
assets.bodyTags = this.getInlineChunk(assets.bodyTags, compilation.assets);
// console.log('assets:',assets)
// console.log('assets.headTags:',assets.headTags)
// console.log('assets.bodyTags:',assets.bodyTags)
});
// 删除runtime文件
hooks.afterEmit.tap("InlineChunkWebpackPlugin", () => {
// 3. 从里面将script的runtime文件,变成inline script
Object.keys(compilation.assets).forEach((filepath) => {
if (/runtime(.*)\.js$/g.test(filepath)) {
delete compilation.assets[filepath];
}
});
});
});
}
//定义方法 为了复用
getInlineChunk(tags, assets) {
/*
目前:[
{
tagName: 'script',
voidTag: false,
meta: { plugin: 'html-webpack-plugin' },
attributes: { defer: true, type: undefined, src: 'js/runtime~main.js.js' }
},
]
修改为:
[
{
tagName: 'script',
innerHTML: runtime文件的内容
closeTag: true
},
]
*/
return tags.map((tag) => {
if (tag.tagName !== "script") return tag;//退出 一定要是script标签
// 获取文件资源路径
const filepath = tag.attributes.src;
if (!filepath) return tag;//一定要有文件路径
//assets文件资源
if (!/runtime(.*)\.js$/g.test(filepath)) return tag//包含runtime吗
return {
tagName: "script",
innerHTML: assets[filepath].source(),
closeTag: true,
};
});
}
}
module.exports = InlineChunkWebpackPlugin;
为了匹配度更高,将传递的规则放在配置文件中
new InlineChunkWebpackPlugin([/runtime(.*)\.js$/g])
const path = require("path");
//处理html
const HtmlWebpackPlugin = require("html-webpack-plugin");
//插件需要先引入再使用
const TestPlugin = require("./plugins/test-plugin2");
const BannerWebpackPlugin = require("./plugins/banner-webpack-plugin");
const CleanWebpackPlugin = require("./plugins/clean-webpack-plugin");
const AnalyzeWebpackPlugin = require("./plugins/analyze-webpack-plugin");
const InlineChunkWebpackPlugin = require("./plugins/inline-chunk-webpack-plugin");
module.exports = {
entry: "./src/main.js",//根据找到依赖
output: {
path: path.resolve(__dirname, "./dist"),
filename: "js/[name].js",// filename: 输出文件名
//clean: true,
},
module: {//编译记载配置
rules: [
// {
// test: /\.js$/,//处理js文件
// loader: "./loaders/test-loader.js",//将要处理文件作为参数传到test-loader.js
// },
{
test: /\.js$/,//处理js文件
// use: ["./loaders/demo/test1","./loaders/demo/test2"],
// loader: "./loaders/demo/test3",
// use: ["./loaders/demo/test4","./loaders/demo/test5","./loaders/demo/test6"],
loader: "./loaders/clean-log-loader",
},
{
test: /\.js$/,//处理js文件
loader: "./loaders/banner-loader/index.js",
options:{
author:"老王",
// age:"34"
}
},
{
test: /\.js$/,
loader: "./loaders/babel-loader",
options: {
presets: ["@babel/preset-env"],//传入的预设选项@babel/preset-env
},
},
{
test: /\.(png|jpe?g|gif)$/,
loader: "./loaders/file-loader",
type: "javascript/auto", // 阻止webpack默认处理图片资源,只使用file-loader处理
},
{
test: /\.css$/,
// use: ["style-loader", "css-loader"],
use: ["./loaders/style-loader","css-loader"],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "public/index.html"),
}),
//new TestPlugin(),
new BannerWebpackPlugin({
author: "老王",
}),
new CleanWebpackPlugin(),
new AnalyzeWebpackPlugin(),
new InlineChunkWebpackPlugin([/runtime(.*)\.js$/g])
],
optimization:{
splitChunks:{//代码分割
chunks:'all'
},
runtimeChunk:{
name:entrypoint => `runtime~${entrypoint.name}.js`,
}
},
mode: "production",
};
plugin文件为
const HtmlWebpackPlugin = require("safe-require")("html-webpack-plugin");
class InlineChunkWebpackPlugin {
constructor(tests) {
this.tests = tests;//接收传入的数组
}
apply(compiler) {
compiler.hooks.compilation.tap("InlineChunkWebpackPlugin", (compilation) => {
// 1. 获取html-webpack-plugin的hooks
const hooks = HtmlWebpackPlugin.getHooks(compilation);
// 2. 注册 html-webpack-plugin的hooks -> alterAssetTagGroups
hooks.alterAssetTagGroups.tap("InlineChunkWebpackPlugin", (assets) => {
// 3. 从里面将script的runtime文件,变成inline script
assets.headTags = this.getInlineChunk(assets.headTags, compilation.assets);
assets.bodyTags = this.getInlineChunk(assets.bodyTags, compilation.assets);
});
// 删除runtime文件
hooks.afterEmit.tap("InlineChunkWebpackPlugin", () => {
// 3. 从里面将script的runtime文件,变成inline script
Object.keys(compilation.assets).forEach((filepath) => {
if (this.tests.some((test) => test.test(filepath))) {
delete compilation.assets[filepath];
}
});
});
});
}
getInlineChunk(tags, assets) {
/*
目前:[
{
tagName: 'script',
voidTag: false,
meta: { plugin: 'html-webpack-plugin' },
attributes: { defer: true, type: undefined, src: 'js/runtime~main.js.js' }
},
]
修改为:
[
{
tagName: 'script',
innerHTML: runtime文件的内容
closeTag: true
},
]
*/
return tags.map((tag) => {
if (tag.tagName !== "script") return tag;
// 获取文件资源路径
const filepath = tag.attributes.src;
if (!filepath) return tag;
if (!this.tests.some((test) => test.test(filepath))) return tag;
return {
tagName: "script",
innerHTML: assets[filepath].source(),
closeTag: true,
};
});
}
}
module.exports = InlineChunkWebpackPlugin;