前几篇文章主要是将如何完成一个elpis项目。本文主要是根据抽离点将之前所讲的elpis项目抽离成sdk供其他项目所使用。
-
将启动项目的能力暴露给调用方
scss/** * 服务端基础 */ Controller: { Base: require('./app/controller/base.js') }, Service: { Base: require('./app/service/base.js') }, /** * 编译构建前端工程 * @params env 环境变量 local/production */ frontendBuild(env) { if (env === 'local') { FEBuildDev(); } else if (env === 'production') { FEBuildProd(); } }, /** * 启动elpis * @params options 项目配置,透传到elpis-core */ serverStart(options = {}){ const app = ElpisCore.start(options) return app; }
-
修改工程化的配置
在启动的项目的时候,保留npm包功能的同时可以根据项目配置扩展sdk的工程化能力
- npm包内容的修改
ini// 获取 elpis/app/目录下所有入口文件 const entryList = path.resolve(__dirname,'../../pages/**/entry.*.js');
- 项目内容的扩展
less// 获取 business/app/目录下所有入口文件 const businessList = path.resolve(process.cwd(),'./app/pages/**/entry.*.js'); // 构造 相关webpack 处理的数据结构 function handleFile(file, entries = {}, htmlWbpackPluginList = []){ const entryName = path.basename(file,'.js') // path.basename(path.dirname(filePath)); // 提取页面名称 // 构造entry entries[entryName] = file; // 构造html页面 htmlWbpackPluginList.push(new HtmlWebpackPlugin({ // 辅助注入打包后的bundle文件到tpl文件中 //产物 最终模板输出路径 filename: path.resolve(process.cwd(),'./app/public/dist/',`${entryName}.tpl`), //指定要使用的模板文件 template: path.resolve(__dirname,'../../view/entry.tpl'), // 要注入的代码块 chunks: [entryName] })) }
- 扩展能力
javascript // 加载业务 webpack配置 let businessWebpackConfig = {} try { businessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`) } catch (e) { }
- npm包对npm引入第三方内容的修改
cssmodule: { rules:[ { test: /.vue$/, use: { loader: require.resolve('vue-loader') } },{ test: /.js$/, include: [ // 只对业务代码进行 babel 加快webpack的打包速度 path.resolve(process.cwd(),'./app/pages'), // 处理elpis 目录 path.resolve(__dirname,'../../pages') ], use:{ loader: require.resolve('babel-loader') } }, { test: /.(png|jpe?g|gif)(?.+)?$/, use: { loader: require.resolve('url-loader'), options: { limit: 300, esModule: false } } },{ test: /.css$/, use: [require.resolve('style-loader'),require.resolve('css-loader')] },{ test: /.less/, use: [require.resolve('style-loader'),require.resolve('css-loader'),require.resolve('less-loader')] },{ test: /.(eot|svg|ttf|woff|woff2)(?\S*)?$/, use: require.resolve('file-loader') } ]
-
Elpis-core的配置
核心思想是在获取elpis npm包的同时,可以获取到项目的配置文件。将两组配置混合
-
全局中间件的配置修改
javascript// 注册npm包的全局中间件 const elipsMiddlewarePath = path.resolve(__dirname,`..${sep}app${sep}middleware.js`) const elpisMiddleware = require(elipsMiddlewarePath) elpisMiddleware(app) // 注册项目的全局中间件 try{ require(`${app.businessPath}${sep}middleware.js`)(app) }catch(e){ }
-
Middleware,Router-schema,Controller,Service,extend 的修改大致相同
ini// 读取 /elpis/app/middleware/**/**.js下所有的文件 const elpisMiddlewarePath = path.resolve(__dirname,`..${sep}..${sep}app${sep}xxx`); const elpisFileList = glob.sync(path.resolve(elpisMiddlewarePath,`.${sep}**${sep}**.js`)) elpisFileList.forEach(file => { handleFile(file) }); // 读取 业务根目录/app/middleware/**/**.js下所有的文件 const businessMiddlewarePath = path.resolve(app.businessPath,`.${sep}xxx`); const businessFileList = glob.sync(path.resolve(businessMiddlewarePath,`.${sep}**${sep}**.js`)) businessFileList.forEach(file => { handleFile(file) }); // 把内容加载到 app.middlewares下
-
config配置
javascript// elpis config 目录及相关文件 const elpisConfigPath = path.resolve(__dirname,`..${sep}..${sep}config`) let defaultConfig = require(path.resolve(elpisConfigPath,`.${sep}config.default.js`)) // 获取业务 config 目录及相关文件 // 知道config目录 const businessConfigPath = path.resolve(process.cwd(),`.${sep}config`) try{ defaultConfig = { ...defaultConfig, ...require(path.resolve(businessConfigPath,`.${sep}config.default.js`)) } }catch(error) { if(error.code === 'ENOENT'){ onsole.log('[exception] there is no default.config file'); }else if(error.message?.includes('Syntax error')){ console.log('[exception] default.config Syntax error'); }else{ console.log('[exception] efault.config error'); } }
-
Router
ini// 找到elpis路由文件路径 const elpisRouterPath = path.resolve(__dirname,`..${sep}..${sep}app${sep}router`); // 注册elpis所有路由 const elpisFileList = glob.sync(path.resolve(elpisRouterPath,`.${sep}**${sep}**.js`)); elpisFileList.forEach(file => { handleFile(file) }) // 找到业务路由文件路径 const businessRouterPath = path.resolve(app.businessPath,`.${sep}router`); // 注册业务所有路由 const businessFileList = glob.sync(path.resolve(businessRouterPath,`.${sep}**${sep}**.js`)); businessFileList.forEach(file => { handleFile(file) })
-
-
项目组件和页面的集成
修改webpack的alias 将可能用到的文件配置先定义好,在npm包集成的时候将 项目和npm包的内容集成一起初始化。
scssresolve: { extensions: [ '.vue', '.js', '.less', '.css'], alias: (() => { const aliasMap = {}; const blackModulePath = path.resolve(__dirname, '../libs/blank.js') // dashboard 路由扩展配置 const businessDashboardRouterConfig = path.resolve(process.cwd(), './app/pages/dashboard/router.js'); aliasMap['$businessDashboardRouterConfig'] = fs.existsSync(businessDashboardRouterConfig) ? businessDashboardRouterConfig : blackModulePath // schema-view component扩展配置 const businessComponentConfig = path.resolve(process.cwd(), './app/pages/dashboard/complex-view/schema-view/components/component-config.js'); aliasMap['$businessComponentConfig'] = fs.existsSync(businessComponentConfig) ? businessComponentConfig : blackModulePath // schema-form item 扩展配置 const businessFormItemConfig = path.resolve(process.cwd(), './app/pages/widgets/schema-form/form-item-config.js'); aliasMap['$businessFormItemConfig'] = fs.existsSync(businessFormItemConfig) ? businessFormItemConfig : blackModulePath // schema-search-bar item 扩展配置 const businessSearchItemConfig = path.resolve(process.cwd(), './app/pages/widgets/schema-search-bar/search-item-config.js'); aliasMap['$businessSearchItemConfig'] = fs.existsSync(businessSearchItemConfig) ? businessSearchItemConfig : blackModulePath return { 'vue': require.resolve('vue'), '@babel/runtime/helpers/asyncToGenerator': require.resolve('@babel/runtime/helpers/asyncToGenerator'), '@babel/runtime/regenerator': require.resolve('@babel/runtime/regenerator'), '$elpisPages': path.resolve(__dirname, '../../pages'), '$elpisCommon': path.resolve(__dirname, '../../pages/common'), '$elpisCurl': path.resolve(__dirname, '../../pages/common/curl.js'), '$elpisUtil': path.resolve(__dirname, '../../pages/common/utils.js'), '$elpisWidgets': path.resolve(__dirname, '../../pages/widgets'), '$elpisHeaderContainer': path.resolve(__dirname, '../../pages/widgets/header-container/header-container.vue'), '$elpisSiderContainer': path.resolve(__dirname, '../../pages/widgets/sider-container/sider-container.vue'), '$elpisSchemaTable': path.resolve(__dirname, '../../pages/widgets/schema-table/schema-table.vue'), '$elpisSchemaForm': path.resolve(__dirname, '../../pages/widgets/schema-form/schema-form.vue'), '$elpisSechemaSearchBar': path.resolve(__dirname, '../../pages/widgets/schema-search-bar/schema-search-bar.vue'), '$elpisStore': path.resolve(__dirname, '../../pages/store'), '$elpisBoot': path.resolve(__dirname, '../../pages/boot.js'), ...aliasMap } })() },
- 业务 拓展路由
javascriptimport businessDashboardRouterConfig from '$businessDashboardRouterConfig' if (typeof businessDashboardRouterConfig === 'function') { businessDashboardRouterConfig({routes, siderRoutes}) }
- 业务组件的扩展
javascript// 业务扩展components配置 import BusinessComponentConfig from '$businessComponentConfig' export default { ...ComponentConfig, ...BusinessComponentConfig } //业务扩展 search-item配置 import BusinessSearchItemConfig from '$businessSearchItemConfig' export default { ...SearchItemConfig, ...BusinessSearchItemConfig }
- 基础表单组件的扩展
javascript//业务扩展 form-item 配置 import BusinessFormItemConfig from '$businessFormItemConfig' export default { ...FormItemConfig, ...BusinessFormItemConfig };
-
npm的发布流程
-
登录 npm 终端执行登录命令,输入账号密码:
npm login
注意:如果之前使用过淘宝镜像(如
registry=https://registry.npm.taobao.org
),需先切换回官方源:npm config set registry https://registry.npmjs.org/
-
发布包 在项目根目录执行:
npm publish
arduinonpm publish --access public // 带有前缀的 命名空间第一次发布
成功后会显示发布信息,此时可在 npm 官网 搜索你的包名查看。
-
更新包版本
-
更新版本号(遵循语义化版本):
bashnpm version patch # 修订号 +1(1.0.0 → 1.0.1,修复 bug 时用) npm version minor # 次版本号 +1(1.0.1 → 1.1.0,新增功能时用) npm version major # 主版本号 +1(1.1.0 → 2.0.0,不兼容变更时用)
该命令会自动修改
package.json
的version
字段,并创建 git 标签(如果使用 git)。 -
重新发布:
bashnpm publish # 发布新版本
-
五、删除 / 废弃包(谨慎操作)
-
删除指定版本(发布后 72 小时内可删):
sqlnpm unpublish 包名@版本号 # 例如:npm unpublish my-unique-package@1.0.0
-
废弃包(不删除但标记为不推荐使用):
arduinonpm deprecate 包名 "该包已废弃,请使用 xxx 替代"
-
经过这次项目的完成,让我对前端这块的内容有了一个梳理.对于后续提升自己的能力有了一个大致的方向。
备注引用: 抖音"哲玄前端"《大前端全栈实践》