@vue/cli 插件开发之自动根据目录列表生成别名配置

1.相关文档

  1. @vue/cli官方文档 @vue/cli
  2. @vue/cli插件开发指南 @vue/cli

2.插件命名规范

为了让一个 CLI 插件在 Vue CLI 项目中被正常使用,它必须遵循 vue-cli-plugin- 或者 @scope/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

  1. 初始化仓库
    使用pnpm init初始化目录
  2. 安装相关依赖
  • 代码规范插件
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
  1. 完善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"
    }
}
  1. 初始话tsconfig.json
{
    "compilerOptions": {
        "target": "esnext",
        "useDefineForClassFields": true,
        "lib": ["ESNext", "DOM"],
        "moduleResolution": "Node",
        "strict": true,
        "module": "esnext"
    },
    "include": ["src/**/*"],
    "exclude": ["node_modules", "**/*.spec.ts"]
}
  1. 增加打包配置文件
// 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']
});
  1. 插件核心代码逻辑
    @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 }
            }
        };
    });
}
posted @ 2023-02-01 09:59  半糖也甜吖  阅读(134)  评论(0编辑  收藏  举报