随着前端技术的不断发展,Vue.js 已经成为了一个非常流行的 JavaScript 框架,它使得开发者能够更高效地构建用户界面。在 Vue.js 的生态系统中,插件扮演着重要的角色,它们能够扩展框架的功能,提高开发效率。对于开发者来说,掌握如何创建和使用插件是非常重要的,本文将介绍如何基于 Vue2+JS
实现自己的插件。
需要实现的命令:
- 创建组件: yarn add:component 组件名称 组件中文名
- 删除组件: yarn del:component 组件名称
- 构建国际化: yarn build:lang
- 构建样式: yarn build:style
- 构建导出文件: yarn build:entry
- 执行完 yarn add:component 或 yarn del:component 后要执行 yarn build:entry 命令
1. 初始化项目
使用 vue/cli 3
进行初始化项目,执行命令:vue3 create qiuer-resource-vue2-js
(为什么是vue3,可以参考: (超详细)在同一设备下安装不同版本的vue脚手架笔记)
D:\dataGitMy\qiuer\qiankun-all\workspaces>vue3 create qiuer-resource-vue2-js
Vue CLI v3.11.0
┌───────────────────────────┐
│ Update available: 5.0.8 │
└───────────────────────────┘
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: Basic
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
Vue CLI v3.11.0
✨ Creating project in D:\dataGitMy\qiuer\qiankun-all\workspaces\qiuer-resource-vue2-js.
⚙ Installing CLI plugins. This might take a while...
yarn install v1.22.22
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
success Saved lockfile.
Done in 16.27s.
🚀 Invoking generators...
📦 Installing additional dependencies...
yarn install v1.22.22
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 9.29s.
⚓ Running completion hooks...
📄 Generating README.md...
🎉 Successfully created project qiuer-resource-vue2-js.
👉 Get started with the following commands:
$ cd qiuer-resource-vue2-js
$ yarn serve
生成的目录结构如下:
├── node_modules
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── views
│ │ ├── About.vue
│ │ └── Home.vue
│ ├── App.vue
│ ├── main.js
│ ├── router.js
│ └── store.js
├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── babel.config.js
├── package.json
├── postcss.config.js
├── README.md
└── yarn.lock
执行: yarn add element-ui
安装 element-ui 依赖
2. 文件操作的工具方法 ./build/utils/ToolsFile.js
安装相关依赖,执行命令: yarn add uppercamelcase file-save json-templater -D
/**
* @description: 文件和文件夹操作
*/
const fs = require('fs');
const path = require('path');
const fsPromises = fs.promises;
// 同步判断目录是否存在
function dirIsExistsSync(dirPath){
if (fs.existsSync(dirPath)) {
console.log(`${dirPath} 目录存在`);
return true;
} else {
console.log(`${dirPath} 目录不存在`);
return false;
}
}
// 同步创建文件夹
function createFolderSync (folderPath) {
try {
fs.mkdirSync(folderPath, { recursive: true });
console.log(`${folderPath} 同步创建文件夹成功!`);
return true;
} catch (err) {
console.error(`${folderPath} 同步创建文件夹失败: `, err);
return false;
}
}
module.exports = {
/**
* 判断目录是否存在-同步
* 同步判断目录是否存在
* directoryPath : 要判断的目录
* 使用示例: const a = dirIsExistsSync('./examples1/c.txt')
*/
dirIsExistsSync: (directoryPath) => {
return dirIsExistsSync(directoryPath)
},
/**
* 创建文件-同步
* 创建文件, 同步创建并写入文件内容
* filePath : 要创建的文件
* content : 文件内容
* 使用示例: writeFileSync('./examples/demo/d.md', '# Hello, \n this is a new file!')
*/
writeFileSync(filePath, content){
const lastDirName = filePath.split('/').reverse()[0];
const isFile = lastDirName.lastIndexOf('.'); // 用于判断是否是文件
if(isFile === -1) {
console.log(`${filePath} 不是文件路径`);
return false;
}
const fileIsExists = dirIsExistsSync(filePath) // 文件是否存在
if(!fileIsExists) {
const dir = filePath.substring(0, filePath.lastIndexOf('/') > -1 ? filePath.lastIndexOf('/') : filePath.lastIndexOf('\\'));
const dirIsExists = dirIsExistsSync(dir) // 文件夹是否存在
if(dir && !dirIsExists) {
createFolderSync(dir)
}
}
try {
// 创建并写入文件内容
fs.writeFileSync(filePath, content);
console.log(`${filePath} 文件创建成功`);
return true;
} catch (err) {
console.error(`${filePath} 创建文件失败:`, err);
return false;
}
},
/**
* 创建文件夹-同步
* folderPath : 要创建的文件夹路径
* 使用示例: createFolderSync('./examples')
*/
createFolderSync: (folderPath) => {
try {
fs.mkdirSync(folderPath, { recursive: true });
console.log(`${folderPath} 同步创建文件夹成功!`);
return true;
} catch (err) {
console.error(`${folderPath} 同步创建文件夹失败: `, err);
return false;
}
},
/**
* 文件内容覆写-同步
* 覆写文件,覆盖整个文件内容-同步
* filePath : 要操作的文件路径
* content : 要新写的内容
* 使用示例: fileRewriteSync('./test/a.txt', '这是要追加的内容 \n')
*/
fileRewriteSync: (filePath, content) => {
try {
fs.writeFileSync(filePath, content);
console.log(`${filePath} 内容覆盖成功`);
return true;
} catch (err) {
console.error(`${filePath} 覆盖内容失败:`, err);
return false;
}
},
/**
* 文件内容追加-同步
* 在已存在的文件中追加内容-同步
* filePath : 要操作的文件路径
* content : 要追加的内容
* 使用示例: fileAppendContentSync('./test/a.txt', '这是要追加的内容 \n')
*/
fileAppendContentSync: (filePath, content) => {
try {
fs.appendFileSync(filePath, content + '\n');
console.log(`${filePath} 内容追加成功`);
return true;
} catch (err) {
console.error(`${filePath} 追加内容失败:`, err);
return false;
}
},
/**
* 删除文件/文件夹
* @param {string} dirPath - 要删除的路径
* @returns
*/
delFileFolder: (dirPath) => {
// 判断路径是否存在
if(!fs.existsSync(dirPath)) {
console.log(`${dirPath} 路径不存在`);
return;
}
// 判断路径是否为文件
let isFile = false;
try {
const stats = fs.statSync(dirPath);
isFile = !!stats.isFile();
} catch (err) {
if (err.code === 'ENOENT') {
// 文件或文件夹不存在
console.error(`路径 ${dirPath} 不存在`);
isFile = false;
}
throw err; // 抛出其他未知错误
}
if(isFile) {
try {
fs.unlinkSync(dirPath);
console.log(`文件 ${dirPath} 已经被成功删除.`);
} catch (err) {
console.error(`删除文件 ${dirPath} 失败:`, err);
}
return;
}
// 同步删除文件夹
function delFolder(delPath){
try {
const files = fs.readdirSync(delPath);
files.forEach(file => {
const curPath = path.join(delPath, file);
const stats = fs.statSync(curPath);
if (stats.isDirectory()) {
// 递归删除子文件夹
delFolder(curPath);
} else {
// 删除文件
fs.unlinkSync(curPath);
}
});
// 删除空文件夹
fs.rmdirSync(delPath);
console.log(`文件夹 ${delPath} 及其内容已被删除.`);
} catch (err) {
if (err.code === 'ENOENT') {
console.error(`路径 ${delPath} 不存在`);
} else {
throw err;
}
}
}
delFolder(dirPath)
},
deleteFolder: async (folderPath) => {
async function fn(dirPath){
if(!dirIsExistsSync(dirPath)) {
console.log(`${dirPath} 目录不存在`);
return;
}
try {
// 获取文件夹中的所有文件和子文件夹
const files = await fs.promises.readdir(dirPath, { withFileTypes: true });
// 递归删除每个文件或子文件夹
for (const file of files) {
const filePath = path.join(dirPath, file.name);
if (file.isDirectory()) {
// 如果是文件夹,递归删除
await fn(filePath);
} else {
// 如果是文件,直接删除
await fs.promises.unlink(filePath);
}
}
// 删除空文件夹
await fs.promises.rmdir(dirPath);
console.log(`${dirPath} 异步删除文件夹成功!`);
} catch (err) {
console.error(`${dirPath} 删除文件夹失败:`, err);
throw err;
}
}
fn(folderPath);
},
/**
* 文件内容修改-异步
* 修改文件中指定内容
* filePath : 要操作的文件路径
* oldContent : 要替换的字符串
* newContent : 新的字符串
* 使用示例: replaceFileContent('./test/a.txt', '哈哈', '嘿嘿')
*/
replaceFileContent(filePath, oldContent, newContent){
fs.readFile(filePath, (err, data) => {
if(err) throw err;
let fileContent = data.toString();
let modifiedContent = fileContent.replace(oldContent, newContent)
fs.writeFile(filePath, modifiedContent, (e) => {
if(e) throw e;
console.log(`文件修改成功!`);
})
})
},
/**
* 获取指定文件夹下的文件列表-同步
* dir : 路径
* cb : 回调函数
*/
getDirFilesListSync: (dir, cb) => {
const arr = [];
const files = fs.readdirSync(dir);
files.forEach(filename => {
const filedir = path.join(dir, filename);
if(fs.statSync(filedir).isFile()) {
arr.push(filename)
}
});
cb(arr)
},
}
3. 新增/删除组件时所要处理的文件配置 ./build/utils/newDelCompFiles.js
/**
* 新增/删除 组件是要新增/删除的文件配置
*/
const path = require('path')
function getFilesConfig(CompName, componentName) {
return [
{
filename: 'index.js',
content: `import ${CompName} from './src/index';
/* istanbul ignore next*/
${CompName}.install = function(Vue) {
Vue.component(${CompName}.name, ${CompName});
};
export default ${CompName};
`
},
{
filename: 'readme.md',
content: `# ${CompName}
组件介绍
`
},
{
filename: 'src/index.vue',
content: `<template>
<div class="${camelCaseToHyphen(componentName)}">
${componentName}
</div>
</template>
<script>
export default {
name: '${CompName}',
components: {},
props: {},
provide: function(){
return {};
},
inject: [],
data(){
return {};
},
computed: {},
watch: {},
created() {},
mounted() {},
beforeDestroy() {},
methods: {},
}
</script>
<style lang="scss" scoped>
</style>
`,
},
{
filename: 'src/initConfig.js',
content: '',
},
{
filename: 'styles/index.scss',
content: '',
},
{
filename: 'index.scss',
content: `@import './styles/index.scss';`,
},
{
filename: path.join('../../examples/template', `${componentName}/index.vue`),
content: `<template>
<div class="comp-example-container">
<${CompName} />
</div>
</template>
<script>
export default {
name: '',
components: {},
props: {},
provide: function(){
return {};
},
inject: [],
data(){
return {};
},
computed: {},
watch: {},
created(){},
mounted() {},
beforeDestroy() {},
methods: {},
}
</script>
<style lang='scss' scoped>
</style>
`,
},
{
filename: path.join('../../src/i18ns/en/', `${componentName}.js`),
content: `export default {
${componentName}: {},
}`
},
{
filename: path.join('../../src/i18ns/zh-CN/', `${componentName}.js`),
content: `export default {
${componentName}: {},
}`
},
{
filename: path.join('../../src/services/', `${componentName}/API.js`),
content: `import ComponentAPI from '../ComponentAPI.json';
const API = {};
export default API;
`,
},
{
filename: path.join(`../../src/services/`, `${componentName}/index.js`),
content: `import API from './API';
import HttpClientHelper from '../../utils/httpClientHelper';
class ${CompName}Service {}
export default new ${CompName}Service();
`,
}
];
}
/**
* [camelCaseToHyphen 将驼峰命名转换为连字符]
* @param {[string]} str [驼峰命名的字符串]
* @return {[string]} [连字符的字符串]
*/
function camelCaseToHyphen(str) {
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
}
module.exports = getFilesConfig;
4. 命令脚本文件 ./build/bin/new-comp.js
'use strict';
/**
* 执行命令示例: yarn add:component testComp 测试组件
* yarn add:component 组件名称 组件中文名
* new.js脚本主要做了下面几件事:
* 1. 创建一些需要提前准备的目录
* 2. 将新建的组件添加到 components.json
* 3. 将新建的组件添加到 exposeComponents.json
* 4. 根据配置在 packages 下创建相关的文件及文件夹
* 5. 重写 service/index.js 文件
*/
// process.on() 方法可以监听进程事件
process.on('exit', () => {
console.log('当进程要退出之前,会触发exit事件。');
})
/**
* process.argv:返回一个数组
* 其中包含当 Node.js 进程被启动时传入的命令行参数
* 第一个元素是 process.execPath
* 第二个元素是正被执行的 JavaScript 文件的路径
* 其余的元素是任何额外的命令行参数
*/
if(!process.argv[2]) {
console.log('参数:', process.argv);
console.error('[组件名]必填 - Please enter new component name');
process.exit(1);
}
const path = require('path')
const uppercamelcase = require('uppercamelcase')
const componentName = process.argv[2]
const ComponentName = uppercamelcase(componentName);
const componentCnName = process.argv[3] || componentName
const PackagePath = path.resolve(__dirname, '../../packages', componentName)
const ToolsFile = require('../utils/ToolsFile');
// 要创建的文件
const getFilesConfig = require('../utils/newDelCompFiles')
const Files = getFilesConfig(ComponentName, componentName);
/******** 需要提前准备的一些文件或目录 start ********/
const prepareDirs = [
'./exposeComponents.json',
'./components.json',
'./examples/template',
'./packages',
'./src/i18ns/en',
'./src/i18ns/zh-CN',
'./src/services',
'./src/services/index.js',
];
prepareDirs.forEach(dir => {
const lastDirName = dir.split('/').reverse()[0];
const isFile = lastDirName.lastIndexOf('.'); // 用于判断是否是文件
const isExists = ToolsFile.dirIsExistsSync(dir); // 目录是否存在
if(!isExists) {
if(isFile > -1) {
const fileSuffix = lastDirName.substr(isFile+1)
const fileContent = fileSuffix === 'json' ? '{}' : '';
ToolsFile.writeFileSync(dir, fileContent)
} else {
ToolsFile.createFolderSync(dir)
}
}
});
console.log('目录准备完成!')
/******** 需要提前准备的一些文件或目录 end ********/
/******** 添加到 components.json start ********/
const componentsFile = require('../../components.json');
if(componentsFile[componentName]) {
console.error(`${componentName} 已存在`)
process.exit(1);
}
componentsFile[componentName] = {
url: `./packages/${componentName}/index.js`,
alias: componentCnName,
};
ToolsFile.fileRewriteSync(path.join(__dirname, '../../components.json'), JSON.stringify(componentsFile, null, ' '));
console.log('添加到 components.json 完成!')
/******** 添加到 components.json end ********/
/******** 添加到 exposeComponents.json start ********/
const exposesFile = require('../../exposeComponents.json');
exposesFile[`./${componentName}`] = `./packages/${componentName}/src/index.vue`;
ToolsFile.fileRewriteSync(path.join(__dirname, '../../exposeComponents.json'), JSON.stringify(exposesFile, null, ' '));
console.log('添加到 exposeComponents.json 成功');
/******** 添加到 exposeComponents.json end ********/
/******** 在 packages 下创建相关文件 start ********/
Files.forEach(file => {
ToolsFile.writeFileSync(path.join(PackagePath, file.filename), file.content);
})
console.log('packages DONE!')
/******** 在 packages 下创建相关文件 end ********/
/******** services/index.js start ********/
ToolsFile.fileAppendContentSync(
path.join(__dirname, '../../src/services/index.js'),
`export { default as ${uppercamelcase(ComponentName)}Service } from './${componentName}'; \n`
);
/******** services/index.js end ********/
5. 命令脚本文件 ./build/bin/del-comp.js
'use strict';
/**
* 执行命令示例: yarn del:component testComp
* yarn del:component 组件名称
*/
// process.on() 方法可以监听进程事件
process.on('exit', () => {
console.log('当进程要退出之前,会触发exit事件。');
})
/**
* process.argv:返回一个数组
* 其中包含当 Node.js 进程被启动时传入的命令行参数
* 第一个元素是 process.execPath
* 第二个元素是正被执行的 JavaScript 文件的路径
* 其余的元素是任何额外的命令行参数
*/
if(!process.argv[2]) {
console.error('[要删除的组件名]必填 - Please enter new component name');
process.exit(1);
}
const path = require('path')
const fs = require('fs')
const fileSave = require('file-save')
const uppercamelcase = require('uppercamelcase')
const componentName = process.argv[2]
const ComponentName = uppercamelcase(componentName);
const componentCnName = process.argv[3] || componentName
const PackagePath = path.resolve(__dirname, '../../packages', componentName)
const ToolsFile = require('../utils/ToolsFile');
// 要删除的文件
const getFilesConfig = require('../utils/newDelCompFiles')
const Files = getFilesConfig(ComponentName, componentName);
/******** 删除 components.json 中指定的组件 start ********/
const componentsFile = require('../../components.json');
if(componentsFile[componentName]) {
delete componentsFile[componentName];
}
ToolsFile.fileRewriteSync(path.join(__dirname, '../../components.json'), JSON.stringify(componentsFile, null, ' '));
console.log('components.json 操作完成!')
/******** 删除 components.json 中指定的组件 end ********/
/******** 删除 exposeComponents.json 中指定的组件 start ********/
const exposesFile = require('../../exposeComponents.json');
delete exposesFile[`./${componentName}`];
ToolsFile.fileRewriteSync(path.join(__dirname, '../../exposeComponents.json'), JSON.stringify(exposesFile, null, ' '));
console.log('exposeComponents.json 操作完成!')
/******** 删除 exposeComponents.json 中指定的组件 end ********/
// 删除相应文件
Files.forEach(file => {
ToolsFile.delFileFolder(path.join(PackagePath, file.filename))
})
const delDirs = [
`./examples/template/${componentName}`,
PackagePath,
`./src/services/${componentName}`,
];
delDirs.forEach(dir => {
ToolsFile.deleteFolder(dir)
})
ToolsFile.replaceFileContent(
path.join(__dirname, '../../src/services/index.js'),
`export { default as ${uppercamelcase(ComponentName)}Service } from './${componentName}'; \n`,
'',
)
console.log('完成删除组件操作!')
6. 命令脚本文件 ./build/bin/build-entry.js
var Components = require('../../components.json');
var fs = require('fs');
var render = require('json-templater/string');
var uppercamelcase = require('uppercamelcase');
var path = require('path');
var endOfLine = require('os').EOL;
/********************* 自定义指令 start **********************/
const ToolsFile = require('../utils/ToolsFile');
const includeDirectivesTmpl = [];
const vueUseDirectivesTmpl = [];
ToolsFile.getDirFilesListSync(path.resolve(__dirname, '../../src/directives'), (arr) => {
arr.forEach(v => {
const directive = v.substring(0, v.lastIndexOf('.'));
includeDirectivesTmpl.push(render('import {{directive}} from \'./directives/{{filename}}\'', {
directive: directive,
filename: v,
}))
vueUseDirectivesTmpl.push(render('Vue.use({{directive}})', {
directive: directive,
filename: v,
}))
})
})
/********************* 自定义指令 end **********************/
var OUTPUT_PATH = path.join(__dirname, '../../src/index.js');
var IMPORT_TEMPLATE = 'import {{name}} from \'../packages/{{package}}/index.js\'';
var INSTALL_COMPONENT_TEMPLATE = ' {{name}}';
var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */
/*** 组件引入 start ***/
{{include}}
/*** 组件引入 end ***/
/*** 指令引入 start ***/
{{importDirectives}}
/*** 指令引入 end ***/
// import './styles/index.less'
// import QiuerUiLang from './i18ns/index' // 导出国际化文件
// import QiuerUiStore from './store/index' // 导出store
// import locale from './locale'
const components = [
{{install}}
]
const install = function (Vue, opts = {}) {
// locale.i18n(opts.i18n)
components.forEach(component => {
Vue.component(component.name, component)
})
// 注册全局指令 start
{{useDirectives}}
// 注册全局指令 end
}
/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export {
install,
// QiuerUiLang,
// QiuerUiStore,
{{list}}
}
export default {
version: '{{version}}',
install,
// locale: locale.use,
// i18n: locale.i18n,
{{list}}
}
`;
delete Components.font;
var ComponentNames = Object.keys(Components);
var includeComponentTemplate = [];
var installTemplate = [];
var listTemplate = [];
ComponentNames.forEach(name => {
var componentName = uppercamelcase(name);
includeComponentTemplate.push(render(IMPORT_TEMPLATE, {
name: componentName,
package: name
}));
if (['Loading', 'MessageBox', 'Notification', 'Message', 'InfiniteScroll'].indexOf(componentName) === -1) {
installTemplate.push(render(INSTALL_COMPONENT_TEMPLATE, {
name: componentName,
component: name
}));
}
if (componentName !== 'Loading') listTemplate.push(` ${componentName}`);
});
var template = render(MAIN_TEMPLATE, {
include: includeComponentTemplate.join(endOfLine),
install: installTemplate.join(',' + endOfLine),
version: process.env.VERSION || require('../../package.json').version,
list: listTemplate.join(',' + endOfLine),
importDirectives: includeDirectivesTmpl.join(endOfLine),
useDirectives: vueUseDirectivesTmpl.join(endOfLine),
});
fs.writeFileSync(OUTPUT_PATH, template);
console.log('[build entry] DONE:', OUTPUT_PATH);
7. 命令脚本文件 ./build/bin/build-style.js
var Components = require('../../components.json');
var fs = require('fs');
var render = require('json-templater/string');
var path = require('path');
var endOfLine = require('os').EOL;
var OUTPUT_PATH = path.join(__dirname, '../../src/styles/components.less');
var IMPORT_TEMPLATE = '@import \'../../packages/{{package}}/index.less\';';
var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-style.js' */
{{include}}
`;
delete Components.font;
function fileExists(filePath) {
try {
return fs.statSync(filePath).isFile();
} catch (err) {
return false;
}
}
var ComponentNames = Object.keys(Components);
var includeComponentTemplate = [];
// includeComponentTemplate.push(render('@import \'../../src/styles/{{name}}.less\';', {
// name: 'common'
// }));
ComponentNames.forEach(name => {
var filePath = path.resolve(__dirname, "../../packages/" + name + "/index.less");
if (fileExists(filePath)) {
includeComponentTemplate.push(render(IMPORT_TEMPLATE, {
package: name
}));
}
});
var template = render(MAIN_TEMPLATE, {
include: includeComponentTemplate.join(endOfLine),
});
fs.writeFileSync(OUTPUT_PATH, template);
8. 命令脚本文件 ./build/bin/build-lang.js
var fs = require('fs');
var render = require('json-templater/string');
var path = require('path');
var endOfLine = require('os').EOL;
var OUTPUT_PATH = path.join(__dirname, '../../src/i18ns/index.js');
var IMPORT_TEMPLATE = `import deepmerge from 'deepmerge';
const lang = {};`;
var REQUIRE_TEMPLATE = `const {{ctxName}} = require.context('./{{langType}}', true, /\.ts$/);
lang['{{langType}}'] = {{ctxName}}.keys().reduce((total, key) => deepmerge(total, {{ctxName}}(key).default), {});`;
var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-lang.js' */
{{include}}
export default lang;
`;
var filePath = path.resolve(__dirname, '../../src/i18ns');
var files = fs.readdirSync(filePath)
var langList = [];
files.forEach(function (item, index) {
if (item !== 'index.js') {
langList.push(item)
}
})
var includeLangType = [];
includeLangType.push(IMPORT_TEMPLATE);
langList.forEach((item, index) => {
includeLangType.push(render(REQUIRE_TEMPLATE, {
ctxName: `ctx${index}`,
langType: item
}))
})
var template = render(MAIN_TEMPLATE, {
include: includeLangType.join(endOfLine),
});
fs.writeFileSync(OUTPUT_PATH, template);
9. 将src相关的文件移动到 examples 文件夹下
10. 修改项目入口文件为 examples/main.js
修改 vue.config.js
entry: {
main: resolve('examples/main.js') // 修改入口文件
},
11. 最终插件项目的目录结构
├── build
│ └── bin // 存放命令的脚本
│ │ ├── build-entry.js
│ │ ├── build-lang.js
│ │ ├── build-style.js
│ │ ├── del-comp.js
│ │ ├── new-comp.js
│ │ ├── newAndDelCompFiles.js
│ │ └── toolsFile.js
├── examples // 组件的使用示例
│ ├── assets
│ │ └── common.less
│ ├── components
│ │ └── ...
│ ├── i18ns
│ │ ├── en
│ │ │ └── ...
│ │ ├── zh
│ │ │ └── ...
│ │ ├── index.js
│ │ └── local.js
│ ├── imgs
│ │ └── ...
│ ├── router
│ │ └── index.js
│ ├── template
│ │ └── ...
│ ├── utils
│ │ └── ...
│ ├── views
│ │ ├── errorPage
│ │ │ └── index.vue
│ │ ├── layout
│ │ │ ├── aside.vue
│ │ │ └── index.vue
│ │ ├── login
│ │ │ └── index.vue
│ │ └── index.vue
│ ├── App.vue
│ └── main.js
├── node_modules
├── packages // 存放各个组件
│ ├── ...
│ └── ...
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── directives // 存放要导出的指令
│ │ ├── ...
│ │ └── ...
│ ├── i18ns
│ │ ├── en
│ │ ├── zh-CN
│ │ └── index.js
│ ├── locale
│ │ ├── lang
│ │ │ ├── en.js
│ │ │ └── zh-CN.js
│ │ ├── format.js
│ │ └── index.js
│ ├── services
│ │ ├── ...
│ │ └── ...
│ ├── store
│ │ ├── ...
│ │ └── ...
│ ├── styles
│ │ ├── common.less
│ │ ├── components.less
│ │ ├── index.less
│ │ └── var.less
│ ├── utils
│ │ ├── ...
│ │ └── ...
│ ├── views
│ │ ├── About.vue
│ │ └── Home.vue
│ ├── App.vue
│ ├── main.js
│ ├── router.js
│ └── store.js
├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── babel.config.js
├── components.json
├── exposeComponents.json
├── package.json
├── postcss.config.js
├── README.md
├── vue.config.js
└── yarn.lock
12. examples 模块下的结构:
├── ...
├── examples
│ ├── assets
│ │ └── common.less
│ ├── components
│ │ └── ...
│ ├── i18ns
│ │ └── ...
│ ├── imgs
│ │ └── ...
│ ├── router
│ │ └── index.js
│ ├── template
│ │ └── ...
│ ├── utils
│ │ └── ...
│ ├── views
│ │ ├── errorPage
│ │ │ └── index.vue
│ │ ├── layout
│ │ │ ├── aside.vue
│ │ │ └── index.vue
│ │ ├── login
│ │ │ └── index.vue
│ │ └── index.vue
│ ├── App.vue
│ └── main.js
├── ...
└── ...