@vue/cli 插件开发之自动根据目录列表生成别名配置
1.相关文档
2.插件命名规范
为了让一个 CLI 插件在 Vue CLI 项目中被正常使用,它必须遵循 vue-cli-plugin-
- 被 @vue/cli-service 发现;
- 被其他开发者通过搜索发现;
- 通过 vue add
或者 vue invoke 安装。
命名示例:vue-cli-plugin-auto-alias or @jiangwy/vue-cli-plugin-auto-alias
3. 插件市场
https://www.npmjs.com/search?q=vue-cli-plugin
搜索以vue-cli-plugin
作为关键字的插件名称,则会展示vue-cli-plugin相关插件
4.示例
此示例插件名称为vue-cli-plugin-inject-alias
相关仓库:vue-cli-plugin-inject-alias
- 初始化仓库
使用pnpm init
初始化目录 - 安装相关依赖
- 代码规范插件
pnpm add eslint @jiangwy/eslint-config -D
- ts相关插件
pnpm add typescript @types/node -D
- 打包相关插件
pnpm add rollup rollup-plugin-typescript2 bumpp -D
- 插件依赖包
pnpm add @vue/cli-service -D
- 完善package.json
{
"name": "vue-cli-plugin-inject-alias",
"version": "0.0.4",
"description": "automatically generate alias based on path",
"author": "jiangweiye <jiangweiye@outlook.com> (https://github.com/jwyGithub)",
"license": "MIT",
"homepage": "https://github.com/jwyGithub/vue-cli-plugin-inject-alias",
"keywords": [
"vue",
"vue-cli",
"vue-cli-plugin",
"vue-cli-plugin-alias",
"alias"
],
"exports": {
".": {
"require": "./dist/index.cjs.js"
}
},
"main": "./dist/index.cjs.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"build": "rollup -c",
"release": "npm run build && bumpp package.json --commit --push --tag && npm publish --access=public",
"lint": "eslint ."
},
"peerDependencies": {
"@vue/cli-service": "*"
},
"devDependencies": {
"@jiangweiye/eslint-config": "^0.0.21",
"@types/node": "^18.11.18",
"@vue/cli-service": "~5.0.0",
"bumpp": "^8.2.1",
"eslint": "^8.31.0",
"rollup": "^3.9.1",
"rollup-plugin-typescript2": "^0.34.1",
"typescript": "^4.9.4"
}
}
- 初始话tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"module": "esnext"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
- 增加打包配置文件
// rollup.config.js
const { defineConfig } = require('rollup');
const ts = require('rollup-plugin-typescript2');
module.exports = defineConfig({
input: './src/index.ts',
output: [
{
format: 'cjs',
exports: 'default',
file: 'dist/index.cjs.js'
}
],
plugins: [
ts({
tsconfig: './tsconfig.json',
tsconfigOverride: {
compilerOptions: {
declaration: true,
declarationMap: false,
declarationDir: 'dist',
allowJs: true
},
include: ['src/**/*']
},
clean: true,
useTsconfigDeclarationDir: true
})
],
external: ['@vue/cli-service', 'path', 'fs']
});
- 插件核心代码逻辑
@vue/cli官方提供了插件api注入入口,导出函数,在项目启动的时候,脚手架会在当前项目中查找相关插件,并执行入口函数
function alias(api: PluginAPI) {
// your plugin code
}
插件实现思路,首先获得执行项目的根路径,可以使用官方提供的apiapi.getCwd()
获得,其次使用fs
模块提供的readdirSync
方法获取src目录下的所有文件夹
/**
* @description 获取所有文件夹
* @param path
* @returns
*/
export const getDirs = (path: string): GetDirs => {
try {
const dirs = readdirSync(path);
return dirs.reduce<GetDirs>((result, name) => {
const fullPath = join(path, name);
isDir(fullPath) && result.push({ dirName: name, dirPath: fullPath });
return result;
}, []);
} catch (error: any) {
throw new Error(error);
}
};
通过fs
模块提供的lstatSync(path).isDirectory();
判断是否是文件夹
/**
* @description 是否是文件夹
* @param path
* @returns
*/
export const isDir = (path: string): boolean => {
return lstatSync(path).isDirectory();
};
得到最终所有的文件夹后,生成alias对象
function genAlias(root: string) {
const dirs = getDirs(root);
return dirs.reduce<{ [key: string]: string }>((result, item) => {
const key = `@${item.dirName}`;
const value = item.dirPath;
result[key] = value;
return result;
}, {});
}
最后通过使用api.configureWebpack
方法将生成的alias对象注入最终的项目配置中
function alias(api: PluginAPI) {
const cwd = api.getCwd();
const root = join(cwd, 'src');
if (!hasFile(root)) {
return;
}
api.configureWebpack(config => {
let baseAlias = {};
if (config.resolve && config.resolve.alias) {
baseAlias = config.resolve.alias;
}
return {
resolve: {
alias: { ...genAlias(root), ...baseAlias }
}
};
});
}