微内核架构
内核不变 core有很强的扩展性 有扩展的时候不能每次都修改内核 微内核去驱动插件运行
核心原理
const events = [];
const typeEnum = ['bootstrap','mount','remove']
// 一个最简单的微内核
class Core() {
context = {}
defaultOpts = {
beforeBootstrap: () => {
console.log('beforeBootstrap')
}
bootstraped: () => {
console.log('bootstraped')
}
beforeMount: () => {
console.log('beforeMount')
}
mounted: () => {
console.log('mounted')
}
beforeRemove: () => {
console.log('beforeRemov')
}
removed: () => {
console.log('removed')
}
}
constructor(ots){
this.opts = {...this.defaultOpts, ...opts}
}
addOlugin({type,run}){
event[type] = event[type] || []
event[type].push(run)
}
// 调用
pluginsRun(type){
events[type]?.forEach(fn => fn(this.context))
}
start() {
this.opts.beforeBootstrap()
this.pluginsRun('bootstrap')
this.opts.bootstraped()
this.opts.beforeMount()
this.pluginsRun('mount')
this.opts.mounted()
this.opts.beforeRemove()
this.pluginsRun('remove')
this.opts.removeed()
// typeEnum.forEach(type => {
// pluginsRun(type);
// })
}
end(){
this.opts.beforeRemove()
pluginsRun('remove')
this.opts.removeed()
}
}
export default Core;
// 用户使用
import core form 'Core'
const core = new Core({
beforeBootstrap: () => {}
})
core.addPlugin({
type: 'mount',
run: (context) => {
console.log('this mount a', context)
}
})
core.addPlugin({
type: 'step2',
run: (context) => {
console.log('this mount b', context)
}
})
core.start()
tapable
// 安装:pnpm add tapable
const { SyncHook } = require('tapable');
const hook = new SyncHook(['arg1', 'arg2', 'arg3']);
hook.tap('flag1', (a1, a2, a3) => {
console.log('flag1', a1, a2, a3)
})
hook.tap('flag2', (a1, a2, a3) => {
console.log('flag2', a1, a2, a3)
})
hook.call('hello', 'this is', 'luyi')
const emit = new SyncHook();
const afterEmit = new SyncHook();
const hooks = {
emit
}
webpack
压缩插件
// 安装:pnpm add jszip webpack-source -D --filter --@react-master
const JSzip = require('jszip');
const { RawSource } = require('webpack-sources');
class ZipPlugin {
constructor(options) {
this.options = options;
}
apply(complier) {
let context = this;
complier.hooks.emit.tapAsync('zipPlugin', (compilation, callback) => {
const zip = new JSzip();
// 生成的所有的静态文件,我都给你压缩一下
// emit 阶段,我已经能在 compilation.assets 这里,拿到所有的 要生成的静态文件了。
Object.keys(compilation.assets).forEach((filename) => {
const source = compilation.assets[filename].source();
zip.file(filename, source);
});
zip.generateAsync({ type: 'nodebuffer' }).then(res => {
compilation.assets[context.options.filename] = new RawSource(res);
callback()
})
})
}
}
module.exports = ZipPlugin;
// 使用:webpack.prod.js:
// plugins: [ new ZipPlugin({filename: 'text.html'}) ]
babel 插件:想要改变一些代码的能力的时候
删除代码中的console语句
function sendLog(){
}
// 1. 在外面包一层
const warpSendLog = warpped(sendLog)
const warpped = (fn) => (..rest) => {
// do sth
fn(...rest)
}
warpSendLog()
// 2. 对象重写
const originXHR = window.xhr;
window.xhr = function(...rest) {
// do sth
originXHR.call(window, ...rest)
}
// 3. consoe.log()
// 工程里面已经写了 但是不想再去修改代码
{
// ...
console.log(params)
}
const generate = require('@babel/generator').default;
// 我们想要在调试环境下,把 console.log() 打印出文件的具体的位置 行数、列数。
// parseAST -- traverse -- generator
const consolePlugin = function({ types }) {
return {
visitor: {
// 访问者模式
CallExpression(path) {
const name = generate(path.node.callee).code;
if(['console.log', 'console.info', 'console.error'].includes(name)) {
const { line, column } = path.node.loc.start;
path.node.arguments.unshift(types.stringLiteral(`filepath: ${line}, ${column}`))
}
}
}
}
}
module.exports = consolePlugin;
// 使用: .babelrc "plugins": { "console.logPlugin" }
postCss 插件
js -> babel
css -> postCss
// 主题切换 data-theme
// 基于 color: "#000000"
A {
color: #f3f4f6
}
// 改成:
html[data-theme = "dark"] {
A {
color: #111827
}
}
// 安装插件: pnpm add postcss-nested@^6.0.1 postcss-nesting@^10.2.0 --filter @react-master
// 修改代码的两个库
// 完整代码:
const postcss = require('postcss');
const defaults = {
functionName: 'luyi',
groups: {},
darkThemeSelector: 'html[data-theme="dark"]',
nestingPlugin: null,
}
const resolveColor = (options, theme, group, defaultValue) => {
const [light, dark] = options.groups[group] || [];
return theme === "dark" ? dark : light;
}
module.exports = postcss.plugin('postcss-theme-colors', (options) => {
// 合并一下参数
options = Object.assign({}, defaults, options);
// 匹配字符
const reGroup = new RegExp(`\\b${options.functionName}\\(([^)]+)\\)`, 'g')
return (style, result) => {
const hasPlugin = name =>
name.replace(/^postcss-/, '') === options.nestingPlugin ||
result.processor.plugins.some(p => p.postcssPlugin === name)
const getValue = (value, theme) => {
// match: luyi(gray50);
// group: gray50
// --> 真实的颜色。
return value.replace(reGroup, (match, group) => {
return resolveColor(options, theme, group, match)
})
}
style.walkDecls((decl) => {
const value = decl.value;
// 我去判断一下,这个 value 上,有没有 luyi(*) 这个东西
if(!value || !reGroup.test(value)) {
return;
}
// ##FF0000 color ##0000ff
// 这里的代码,就是一个匹配到了,value 是 luyi(*)
// value 是 luyi(gray50);
// lightValue:#f9fafb; darkValue:#030712
const lightValue = getValue(value, 'light');
const darkValue = getValue(value, 'dark');
// decl 就是一个样式。color: #fff, 的 AST
const darkDecl = decl.clone({ value: darkValue });
let darkRule;
// 使用 nest 插件,生成 dark 的样式
if(hasPlugin('postcss-nesting')) {
darkRule = postcss.atRule({
name: 'nest',
params: `${options.darkThemeSelector} &`
})
} else if(hasPlugin('postcss-nested')) {
darkRule = postcss.rule({
params: `${options.darkThemeSelector} &`
})
} else {
decl.warn(result, 'no plugins nest find')
}
if(darkRule) {
darkRule.append(darkDecl);
decl.after(darkRule);
}
const lightDecl = decl.clone({value: lightValue});
decl.replaceWith(lightDecl);
})
}
})
// 使用: .postcssrc.js "plugins": [ require(',.themePlugin')({groups})]