elpis 一个企业级应用 —— 抽离 npm 包

将框架抽离并发布 NPM 包

在完成完框架的开发后,由于前期在开发框架的过程中编写了部分业务代码来测试整个框架的使用性,因此在我们需要把框架制作成 npm 包的之前,我们需要先把之前的业务代码进行抽离。

抽离业务代码

npm 包的基本描述(框架 package.json 中的内容)

package.json 复制代码
     {
         "name": "xxx", // 包的唯一名字,此名称必须满足 NPM 的命名规范
          "version": "1.0.0", // 包的版本
          "description": "", // 简短的包描述
          "main": "index.js", // 指定包的入口文件,引入包时会执行的文件
          "repository": {}, // 包的仓库地址
          "author": "", // 包的作者
          "license": "ISC", // 包的许可证
          ...
     }

将框架运用为本地包

首先在抽离之前,我们需要先将框架转换为本地包,从而便于在抽离业务代码的过程中能够通过将该框架引入到另一个demo项目来检查抽离是否成功。

  • npm link:将 elpis 软链到当前系统中
  • npm link name(package.json 中的 name) 将 elpis 包通过软链的方式引入到当前项目中

抽离 elpise-core 部分

  1. 在各个 loader 中添加一个新的路径配置。
    • 例如: 原先的配置读取的是 elpis 路径下的文件,需要多读取一个使用 elpis 框架的项目(业务)路径
js 复制代码
elpis 路径:  
     [ __dirname ]/../../app/ [ loader ]
js 复制代码
业务路径:
    process.cwd() / [ loader ]
  1. 将原先挂载的操作封装为函数,然后将业务内容与 elpis 内容都挂载到相应的 loadr 上。

抽离 webpack 部分

  1. 将 dev 和 prod 两个打包方式暴露出去,然后项目就可以通过该函数去执行相应的打包方式。
js 复制代码
frontendBuild(env){
    if(env === 'local'){
        FEBuildDev();
    }else if(env === 'production'){
        FEBuildProd();
    }
},
  1. webpack.base
    • 添加获取业务入口文件的代码(业务文件与 elpis 文件的目录不同),然后将 elpis 和 业务的入口文件都输出到 tpl 文件夹中。
js 复制代码
// 动态构造 elpis 的 entry 和 最终渲染页面文件
const elpisPageEntries = {};
const elpisHtmlWebpackPluginList = [];
// 获取 elpis/app/pages 目录下所有入口文件 入口文件约定(entry.xx.js)
const elpisEntryList = path.resolve(__dirname, '../../pages/**/entry.*.js');
glob.sync(elpisEntryList).forEach(file => {
    handlerFile(file, elpisPageEntries, elpisHtmlWebpackPluginList);
});

// 动态构造 业务的 entry 和 最终渲染页面文件
const businessPageEntries = {};
const businessHtmlWebpackPluginList = [];
// 获取 elpis/app/pages 目录下所有入口文件 入口文件约定(entry.xx.js)
const businessEntryList = path.resolve(process.cwd(), './app/pages/**/entry.*.js');
glob.sync(businessEntryList).forEach(file => {
    handlerFile(file, businessPageEntries, businessHtmlWebpackPluginList);
});

// 构造相关 webpack 处理的数据结构
function handlerFile(file, entries = {}, htmlWebpackPluginList = []) {
    const entryName = path.basename(file, '.js');
    // 构造 entry (入口配置)
    entries[entryName] = file;
    // 构造最终渲染的页面文件 (HtmlWebpackPlugin)
    htmlWebpackPluginList.push(
        // html-webpack-plugin 辅助注入打包后的 bundle 文件到 tpl 文件中
        new HtmlWebpackPlugin({
            // 产物(最终模板) 输出路径
        filename: path.resolve(process.cwd(),'./app/public/dist',`${entryName}.tpl`),
        // 指定要使用的模板文件
        template: path.resolve(__dirname,'../../view/entry.tpl'),
        // 要注入的代码块
        chunks: [ entryName ]
        })
    );
}
  1. 提供一个给予外部配置打包方式的加载,然后与默认的 base 文件融合然后暴露出去,给予不同的打包环境使用。
js 复制代码
let businessWebpackConfig = {};
try{
    businessWebpackConfig = require(`${process.cwd()}/app/webpack.config.js`);
} catch(e){}
// 合并两个配置
module.exports =merge.smart({defaultElpisWebpackConfig},businessWebpackConfig)
  1. 将所有的 loader 都通过 require 的方式进行导入,由于项目的配置不能够解析这些 loader 因此需要通过 require 去使用。
js 复制代码
{
    test:/\.vue$/,
    use: {
        loader: require.resolve('vue-loader')
    }
}
  1. 对业务 js 文件进行处理。
js 复制代码
{
    test:/\.js$/,
    include :[
        // 只针对该路径下的 js 进行处理 (只对业务代码进行 babel ,加快打包数据的速度)
        // 处理 elpis 目录下的 js 文件
        path.resolve(__dirname,'../../pages'),
        // 处理 业务 目录下的 js 文件
        path.resolve(process.cwd(),'./app/pages')
    ],
    use: {
        loader: require.resolve('babel-loader')
    }
}
  1. 别名配置,将框架的别名配置规范化,将 elpis 框架内容与业务内容区分
    • 一些项目无法解析的插件配置 例如: @babel/runtime/helpers/asyncToGenerator
    • 基础配置,在原先的配置下其路径会定位到当前项目下的路径,因此需要做出修改。此类配置的别名需要在前面加上 elpis 从而形成命名规范 例如: Curl => $elpisCurl
    • 公共组件别名配置,此介绍将放在下方进行介绍。

提供公共组件的扩展方式

  1. 配置外部公共组件路径别名,由于我们需要提供给使用者一个扩展公共组件的方法,因此除了原先 elpis 自带的公共组件路径外,还需要配置一个能够读取项目(业务)公共组件路径的方法,但由于用户不一定会配置自定义组件,因此需要编写一个健壮性的路径配置。
js 复制代码
const aliasMap = {};
const blankModulePath = path.resolve(__dirname, '../libs/blank.js');

// dashboard 路由拓展配置
const businessDashBoardRouterConfig = path.resolve(process.cwd(), './app/pages/dashboard/router.js');
aliasMap['$businessDashBoardRouterConfig'] = fs.existsSync(businessDashBoardRouterConfig)? businessDashBoardRouterConfig : blankModulePath;

// 将框架外部的公共组件配置到 aliasMap 中,如果用户没有配置该目录,则用空白模板替代。
// 最终将项目(业务)公共组件配置,同步别名化,但该别名的统一格式为 businessXXX,例如: ComponentConfig => businessComponentConfig 
  1. 配置组件配置文件,读取框架外的公共组件,然后与原先 elpis 的公共组件进行合并。
js 复制代码
// 从配置完成的别名目录中导入业务的组件配置
import BusinessComponentConfig from '$businessComponentConfig'; 

// 将业务公共配置与 elpis 框架公共配置合并
export default {
    ...componentConfig,
    ...BusinessComponentConfig
};

制作 npm 包

  1. 查看是否具有镜像源,如果存在则需要清空。
  2. 清空镜像源。
  3. 登录 npm。
  4. 确认 npm 账号。
  5. 发布 npm 包
js 复制代码
// 查看镜像源
npm config get

// 清空镜像源
npm config set registry

// 登录 npm
npm login

// 确定当前登录的 npm 账号
npm whoami

// 发布 npm 
npm publish --access public  // 公有化提交,第一次提交需要进行公有化提交。私有化的包需要付费。
npm publish 

总结

一个 npm 包需要的内容有:

  • 示例文档: 包括项目的启动方式,组件的扩展编写方式,DSL 文档的标准等,从而帮助使用者正确使用 npm 包
  • 对外暴露的方法: 启动方法,打包方法
  • 模块化的组件: 在暴露一些默认功能的同时,也要给予使用者扩展功能的方式
相关推荐
小兵张健25 分钟前
运用 AI,看这一篇就够了(上)
前端·后端·cursor
不怕麻烦的鹿丸42 分钟前
node.js判断在线图片链接是否是webp,并将其转格式后上传
前端·javascript·node.js
vvilkim1 小时前
控制CSS中的继承:灵活管理样式传递
前端·css
南城巷陌1 小时前
Next.js中not-found.js触发方式详解
前端·next.js
拉不动的猪2 小时前
前端打包优化举例
前端·javascript·vue.js
Bigger2 小时前
Tauri(十五)——多窗口之间通信方案
前端·rust·app
倔强青铜三2 小时前
WXT浏览器插件开发中文教程(3)----WXT全部入口项详解
前端·javascript·vue.js
Aphasia3112 小时前
快速上手tailwindcss
前端·css·面试
程序员荒生2 小时前
基于 Next.js 搞定个人公众号登陆流程
前端·微信·开源
deckcode3 小时前
css基础-选择器
前端·css