文/ 天机阁首席炼器宗师
(云海深处,紫袍道人端坐八卦炉前,三十六道灵力锁链连接虚空)
"昨日尔等习得Loader采气之术,今日当参Plugin造化之功。须知Loader如单兵剑诀,Plugin乃排兵布阵之法!且看这周天星斗大阵——"
第一章:Plugin的渡劫境界
凝气期Plugin(基础道纹)
// 记录构建时间的青铜日晷
class TimePlugin {
apply(compiler) {
compiler.hooks.done.tap('TimePlugin', () => {
console.log(`🕰️ 本次修炼耗时:${Date.now() - startTime}ms`);
});
}
}
筑基期Plugin(因果干涉)
// 修改功德榜(manifest)的生死簿
class ManifestPlugin {
apply(compiler) {
compiler.hooks.emit.tap('Manifest', (compilation) => {
const manifest = {};
for (const name of Object.keys(compilation.assets)) {
manifest[name] = name.split('').reverse().join(''); // 倒转文件名
}
compilation.assets['manifest.json'] = {
source: () => JSON.stringify(manifest),
size: () => JSON.stringify(manifest).length
};
});
}
}
元婴期Plugin(时空逆转)
// 在平行宇宙生成镜像分身(多线程压缩)
const { Compilation } = require('webpack');
class ParallelPlugin {
apply(compiler) {
compiler.hooks.compilation.tap('Parallel', (compilation) => {
compilation.hooks.processAssets.tapPromise({
name: 'Parallel',
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
}, async (assets) => {
await Promise.all(Object.keys(assets).map(async (name) => {
// 每个文件开启独立时空裂隙
const content = assets[name].source();
assets[name] = await compressInParallel(content);
}));
});
});
}
}
第二章:周天星斗大阵——七步炼器法
第一步:引地脉灵气(项目初始化)
mkdir celestial-plugin
cd celestial-plugin
npm init -y
npm install tapable webpack-sources --save
第二步:铸器胚核心(基础结构)
// celestial-plugin.js
const { SyncHook } = require('tapable');
class CelestialPlugin {
constructor(options = { stars: 9 }) {
this.starCount = options.stars;
}
apply(compiler) {
// 注入星辰之力
compiler.hooks = {
...compiler.hooks,
celestial: new SyncHook(['starArray'])
};
}
}
第三步:刻周天星斗(生命周期接入)
apply(compiler) {
// 在environment阶段布阵
compiler.hooks.environment.tap('Celestial', () => {
this.starArray = Array.from({length: this.starCount},
(_,i) => `★第${i+1}天枢星`);
});
// 在emit阶段释放星力
compiler.hooks.emit.tapAsync('Celestial', (compilation, callback) => {
compilation.assets['star-map.txt'] = {
source: () => this.starArray.join('\n'),
size: () => this.starArray.join('\n').length
};
callback();
});
}
第四步:引四象之力(异步事件处理)
compiler.hooks.make.tapPromise('Celestial', async (compilation) => {
await new Promise(resolve => {
// 青龙位注入木系灵气
setTimeout(() => {
compilation.errors.push(new Error('⚠️ 东方青龙苏醒'));
resolve();
}, 1000);
});
});
第五步:抗九天雷劫(单元测试)
const webpack = require('webpack');
describe('渡劫测试', () => {
it('应生成正确的星图', (done) => {
const config = {
plugins: [new CelestialPlugin({ stars: 3 })]
};
webpack(config, (err, stats) => {
const output = fs.readFileSync('dist/star-map.txt', 'utf8');
expect(output).toMatch(/第1天枢星/);
done();
});
});
});
第六步:融器灵神识(类型定义)
// celestial-plugin.d.ts
declare module 'celestial-plugin' {
import { Plugin } from 'webpack';
interface Options {
stars?: number;
}
class CelestialPlugin extends Plugin {
constructor(options?: Options);
}
export = CelestialPlugin;
}
第七步:成先天至宝(发布与集成)
npm login --registry=https://registry.npmjs.org/
npm version major
npm publish --access public
第三章:天道法则
"Plugin修炼五戒:
1️⃣ 勿直接触碰compilation真身(使用Tapable接口)
2️⃣ 异步操作需结太极印(正确处理callback/promise)
3️⃣ 修改assets要留时空印记(维护sourceMap)
4️⃣ 慎用SyncHook以免阻塞天地灵气(避免同步阻塞)
5️⃣ 多插件协同需遵五行相生顺序(注意hook阶段)"
第四章:诛仙剑阵实战
基础阵图(webpack.config.js)
const CelestialPlugin = require('celestial-plugin');
module.exports = {
plugins: [
new CelestialPlugin({
stars: 28, // 对应二十八星宿
phases: {
// 在特定阶段注入星力
beforeRun: (compiler) => {/*...*/},
afterEmit: (compilation) => {/*...*/}
}
})
]
};
合击秘术(多插件协作)
// 四象封印大阵
const plugins = [
new青龙Plugin({ position: '东方' }),
new白虎Plugin({ attack: 9000 }),
new朱雀Plugin({ rebirth: true }),
new玄武Plugin({ defense: '∞' }),
new四象中枢Plugin() // 控制插件执行顺序
];
第五章:域外天魔入侵
魔道案例:
class DemonPlugin {
apply(compiler) {
compiler.hooks.compilation.tap('Demon', (compilation) => {
// 魔染所有资源(错误:直接修改原始assets)
Object.keys(compilation.assets).forEach(name => {
compilation.assets[name] = {
source: () => '天魔夺舍',
size: () => 666
};
});
});
}
}
正道解法:
class PurePlugin {
apply(compiler) {
compiler.hooks.emit.tap('Pure', (compilation) => {
// 正道:通过中间件形式处理
const { RawSource } = require('webpack-sources');
compilation.hooks.processAssets.tap({
name: 'Pure',
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
}, (assets) => {
for (const [name, source] of Object.entries(assets)) {
compilation.updateAsset(name, new RawSource(
`/* 正道封印 */\n${source.source()}`
));
}
});
});
}
}
(突然,天空裂开紫色缝隙,无数webpack配置从天而降)
弟子:"师尊!我的Plugin让构建内存暴涨!"
道人:"痴儿!定是未在合适的hook阶段释放缓存,就像炼丹炉要定时泄压。且看这招——"
道人剑指划出玄奥轨迹,虚空中浮现代码:
compiler.hooks.thisCompilation.tap('Cache', (compilation) => {
compilation.hooks.finishModules.tap('Cache', (modules) => {
// 清理模块缓存
modules.forEach(mod => mod.cleanup());
});
});
飞升天象:
当Plugin修炼至大乘期,可:
- 创造新的Tapable法则(自定义hook)
- 干涉Loader的剑道轨迹(修改moduleGraph)
- 在compiler与compilation间架设虹桥
- 通过stats对象窥探天道轮回
(道人化作万千星光,虚空中浮现最后谜题)
"记住,Plugin之道在于'顺势而为'。如同观星者不会强行改变星辰轨迹,而是通过设置hook节点让万法自然运行......"
(八卦炉轰然打开,飞出金色卷轴:《Loader与Plugin合击秘术——从入门到渡劫》)