elpis之npm包的发布

实现步骤

  1. 区分框架使用者与开发者的路径
  2. 开放入口给框架使用者
  3. 允许框架使用者自定义webpack配置
  4. webpack别名配置
  5. 允许框架使用者自定义组件
  6. 发布到npm

区分路径

使用__dirnameprocess.cwd()区分框架使用与开发的路径

__dirname表示当前文件所在的路径,process.cwd()表示当前程序启动的路径。对于框架使用者来说,应该使用process.cwd()。对于开发者来说,应该使用__dirname

具体实现示例(elpis-core的改造)

module.exports = {
     /**
     * 读取文件
     * @param {string} dirPath
     * @param {string} filePath
     * @param {object} app
     * @returns string[]
     */
    readFile(dirPath, filePath, app) {
        const actualPath = app ? app.businessDir : __dirname
        const assignPath = path.resolve(actualPath, dirPath)
        return glob.sync(path.resolve(assignPath, filePath))
    }
}
module.exports = (app) => {
    // 读取业务/app/controller下所有文件(框架使用者的目录)
    const businessFileList = readFile(`.${sep}controller`, `.${sep}**${sep}**.js`, app)
    // 读取elpis/app/controller下所有文件(开发者的目录)
    const elpisFileList = readFile(`..${sep}..${sep}app${sep}controller`, `.${sep}**${sep}**.js`)
    const controllers = {}
    const handleFile = file => {
        // 提取文件名称
        let name = path.resolve(file)
        // 截取路径
        name = subPath(name, 'controller')
        // 将custom-module/custom-controller -> customModule/customController
        name = toCamelCase(name)
        //挂载controller到app实例
        let tempController = controllers
        const names = name.split(sep) // [customModule, customController]
        for (let i = 0, len = names.length; i < len; i++) {
            if (i === len - 1) {
                const ControllerModule = require(path.resolve(file))(app)
                // 是文件
                tempController[names[i]] = new ControllerModule()
            } else {
                // 文件夹
                if (!tempController[names[i]]) {
                    tempController[names[i]] = {}
                }
                tempController = tempController[names[i]]
            }
        }
    }
    businessFileList.forEach(file => handleFile(file))
    elpisFileList.forEach(file => handleFile(file))
}

以上是controller-loader的改造,其他loader同理

开发入口

const ElpisCore = require('./elpis-core')
// 引入前端工程化构建方法
const FEBuildDev = require('./app/webpack/dev')
const FEBuildProd = require('./app/webpack/prod')

module.exports = {
    /**
     * 启动 elpis
     * @param {Object} options - 项目配置,透传到ElpisCore
     */
    serverStart(options = {}) {
        const app = ElpisCore.start(options)
        return app
    },
    /**
     * 编译构建前端工程
     * @param {String} env 环境变量 dev/prod
     */
    frontedBuild(env) {
        if (env === 'dev') {
            FEBuildDev()
        } else if (env === 'prod') {
            FEBuildProd()
        }
    },
    /**
     * 服务端基础
     */
    Controller: {
        Base: require('./app/controller/base')
    },
    Service: {
        Base: require('./app/service/base')
    }
}

自定义webpack配置

elpis允许使用者在指定目录下新建webpack.config.js文件覆盖elpis的webpack配置,具体实现如下:

// 加载业务webpack 配置
let businessWebpackConfig = {}
try {
    businessWebpackConfig = require(path.resolve(process.cwd(), './app/webpack.config.js'))
} catch (error) {
    console.error('加载业务webpack配置失败:', error)
}

webpack别名配置

为了区分开发者与使用者之间的别名,需要重新配置两者之间的别名,具体如下:

module.exports = {
    resolve: {
        alias: (() => {
            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
                // schema-view 组件拓展配置
                const businessComponentConfig = path.resolve(
                    process.cwd(),
                    './app/pages/dashboard/complex-view/schema-view/components/component-config.js'
                )
                aliasMap['$businessComponentConfig'] = fs.existsSync(businessComponentConfig)
                    ? businessComponentConfig
                    : blankModulePath
                // schema-search-bar 组件拓展配置
                const businessFormItemConfig = path.resolve(
                    process.cwd(),
                    './app/pages/widgets/schema-form/form-item-config.js'
                )
                aliasMap['$businessFormItemConfig'] = fs.existsSync(businessFormItemConfig)
                    ? businessFormItemConfig
                    : blankModulePath

                const businessSearchBarConfig = path.resolve(
                    process.cwd(),
                    './app/pages/widgets/schema-search-bar/schema-item-config.js'
                )
                aliasMap['$businessSearchBarConfig'] = fs.existsSync(businessSearchBarConfig)
                    ? businessSearchBarConfig
                    : blankModulePath
                return {
                    // 解决elpis框架在使用时无法找到vue的问题,表示在elpis中找vue
                    vue: require.resolve('vue'),
                    $elpisPages: path.resolve(__dirname, '../../pages'),
                    $elpisCommon: path.resolve(__dirname, '../../pages/common'),
                    $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'),
                    $elpisSchemaSearchBar: path.resolve(
                        __dirname,
                        '../../pages/widgets/schema-search-bar/schema-search-bar.vue'
                    ),
                    $elpisStore: path.resolve(__dirname, '../../pages/store'),
                    $elpisCurl: path.resolve(__dirname, '../../pages/common/curl.js'),
                    $elpisUtils: path.resolve(__dirname, '../../pages/common/utils.js'),
                    $elpisBoot: path.resolve(__dirname, '../../pages/boot.js'),
                    ...aliasMap
                }
        })()
    }
}

自定义组件配置

框架使用者在使用elpis时可以自己实现具体的组件,elpis会自动将其合并到对应的组件配置对象当中,当框架使用者需要在原来的schema-form组件中拓展新的组件时,就可以在app/widgets/schema-form/complex-view中创建新的组件,然后编写对应的组件配置对象,如下:

const formItemConfig = {
    组件名: {
        component: Vue组件
    }
}
export default formItemConfig

有了以上的配置对象之后,elpis可以自定加载该配置对象,并将其与原来的组件配置对象进行合并,代码如下:

import InputComponent from './complex-view/input/input.vue'
import InputNumberComponent from './complex-view/input-number/input-number.vue'
import SelectComponent from './complex-view/select/select.vue'
import businessFormItemConfig from '$businessFormItemConfig'
const FormItemConfig = {
    input: {
        component: InputComponent
    },
    inputNumber: {
        component: InputNumberComponent
    },
    select: {
        component: SelectComponent
    }
}
export default {
    ...businessFormItemConfig,
    ...FormItemConfig
}

发布到npm

经过以上一系列的改造之后,我们还需要使用npm link命令在本地测试一下,如果没问题才可以发布到npm,npm link的流程如下:

  1. 在elpis的开发目录使用npm link
  2. 创建一个测试目录,使用npm link 包名链接包到本地开始测试

测试完成之后,没问题,开始发布到npm,步骤如下:

  1. 创建npm帐号并登录,可以在npm官网创建帐号并完成登录,也可以创建好帐号之后使用npm login进行登录
  2. npm config get registry确保是官方镜像
  3. npm publish,首次发布,需要加上--access public参数 表示这不是一个私有包

经过以上步骤,就完成了elpis的改造以及npm包的发布

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]