插件机制是如何工作的
前言
作为解决扩展性的普遍方案,很多工具都支持引入插件来应对个性化场景的需求。比如现在已经离不开的webpack
, babel
. 冉冉升起的vite
. 还有我们伴随我们青春的老大哥jquery
. 下面我将尝试用两条叙事线来说明,一条是CLI
,另一条是使用CLI
的项目。
1. 初始化一个极简CLI
初始化一个项目
npm init -y 复制代码
简单装两个依赖,意思一下
npm i webpack minimist -D // minimist这个库是解析命令行参数用的 复制代码
在根目录创建这个CLI
打包时要用的webpack的配置文件
// ./webpack.config.js module.exports = { entry: './index.js', output: { filename: 'bandle.js' } } 复制代码
在package.json
里加入bin
字段
// ./package.json "bin":{ "snowpack":"./bin/index.js" }, 复制代码
创建bin
文件夹,里面创建index.js
, 我们开始写内容
#!/usr/bin/env node // ./bin/.index.js const { join } = require('path') const webpack = require('webpack') // 假设这个`CLI`用`snowpack.config.js`作为配置文件。 const snowpackConfig = 'snowpack.config.js' // 读取webpack配置 const webpackConfig = require('../webpack.config.js') // 命令和函数的映射 const __commands = {} // 这个对象会传给用户传入的函数里 const api = { // 在插件作者传入的函数里会调用registeCommand注册命令 registeCommand: (command, func) => { if(!__commands[command]){ __commands[command] = func } } } ... 复制代码
先写到这里,我们切换故事线,切换之前回顾一下snowpack
的目录结构。
. |-snowpack |-bin | |-index.js |-node_modules |... |-package-lock.json |-package.json 复制代码
2. 创建一个要使用 "snowpack" 的项目
同样先npm init
一下
npm init -y 复制代码
在根目录创建一个index.js
, 并随便写一写代码
// ./index.js console.log('im test project') 复制代码
在根目录创建一个snowpack
的配置文件
// ./snowpack.config.js const { clean } = require('./plugins.js') module.exports = { plugins:{ commands: [clean('cleaned')] } } 复制代码
再把plugins.js
写一写
// ./plugins.js module.exports = { clean: (str) => (api) => { // 这里接收api对象 api.registeCommand('clean', () => { console.log('exec plugin', str) }) } } 复制代码
最后看一下目录结构
. |-testProject |-index.js |-package.json |-plugins.js |-snowpack.config.js 复制代码
3. 补上 ./bin/index.js 剩余部分
第一节我们写到这里,通过第二节我们知道了snowpack.config.js
的内容,和api
对象会被传到哪里。
// ./bin/.index.js const { join } = require('path') const webpack = require('webpack') // 假设这个`CLI`用`snowpack.config.js`作为配置文件。 const snowpackConfig = 'snowpack.config.js' // 读取webpack配置 const webpackConfig = require('../webpack.config.js') // 命令和函数的映射 const __commands = {} // 这个对象会传给用户传入的函数里 const api = { // 在插件作者传入的函数里会调用registeCommand注册命令 registeCommand: (command, func) => { if(!__commands[command]){ __commands[command] = func } } } ... 复制代码
好,接着往下写
// ./bin/.index.js ... // 封装一个执行webpack打包的函数 const runWebpackBuild = () => { webpack(webpackConfig, (err, status) => { if(err || status.hasErrors()){ console.log('build failed') } console.log('build success') }) } // 读取用户项目的配置文件 const readLocalOptions = () => { return new Promise((resolve, reject) => { const options = require(join(process.cwd(), snowpackConfig)) || {} // commands 就是用户传入的函数数组 const { plugins: {commands = []} = {}} = options if(commands.length > 0){ for(command of commands){ // 调用用户传入的函数时把api暴露出去 command(api) } } resolve(__commands) }) } // 使用minimist把cli命令的参数提取出来 const minimist = require('minimist') const args = minimist(process.argv.slice(2)) // 调用readLocalOptions,执行传入的命令参数 readLocalOptions().then((__commands)=>{ const arg = args._[0] const func = __commands[arg] // 传入的参数如果存在就执行 if(func){ func() }else{ // 没有就走默认打包逻辑 runWebpackBuild() } }) 复制代码
3. 让我们康康效果
敲到这里就差不多了,先到snowpack
目录下执行npm link
npm link 复制代码
再到testProject
目录npm link snowpack
, 建立软连接
npm link snowpack 复制代码
此时的目录
. |-testProject |-node_modules | |-.bin | |-snowpack |-index.js |-package-lock.json |-package.json |-plugins.js |-snowpack.config.js 复制代码
在命令行输入snowpack
xuxuefeng@xuxuefengdeMacBook-Pro-2 testProject % snowpack build success 复制代码
在命令行输入snowpack clean
xuxuefeng@xuxuefengdeMacBook-Pro-2 testProject % snowpack clean exec plugin cleaned 复制代码
嗯,运行正常
作者:snowPeak
链接:https://juejin.cn/post/7021067291852800013