开发uni-app组件包

2,205 阅读4分钟

参考 github.com/dcloudio/un… 进行封装

首先创建一个普通uni-app项目

vue create -p dcloudio/uni-preset-vue my-project

选择默认模板即可

文件目录及说明


|-build
|   |-build-lib.js 构建脚本
|-docs 组件文档
|-packages 打包后的文件夹(上传到npm的内容)
|-public 公共资源文件
|-src
|   |-components 组件文件(会被打包到packages文件夹中)
|
|-.all-contributorsrc 贡献者配置
|-.hjtvuese.config.js 自动生成文档配置

编写组件

src/components 中编写组件文件

例如:src/components/CmpA/CmpA.vue

<template>
    <view>{{ text }}</view>
</template>

<script>
export default {
    props: {
        text: {
            type: String,
            default: 'Hello',
        }
    },
};
</script>
  • 由于组件仅用于小程序,不支持Vue.use形式安装,所以不需要额外的文件适配vue install

准备packages文件夹

在根目录下创建packages文件夹,该文件夹为我们最终上传到NPM的文件夹。

  1. 在packages文件夹中创建package.json
{
    "name": "项目名称,比如mp-ui",
    "private": false,
    "version": "1.0.0",
    "description": "描述",
    "author": "作者",
    "homepage": "主页",
    "license": "Apache-2.0",
    "publishConfig": {
        "access": "public"
    },
    "repository": {
        "type": "git",
        "url": "仓库地址"
    },
    "dependencies": {},
    "devDependencies": {},
    "browserslist": [
        "Android >= 4",
        "ios >= 8"
    ],
}
  1. LICENSE放入

LICENSE文件可以到opensource.org/licenses这里根据项目copy。

LICENSE的区别请查阅其他资料了解。

编写打包发布脚本

1. 先整理我们需要的文件目录

build/dirName.js

const path = require('path');
// 定义目录
// 源components
const packages = path.join(__dirname, '../src/components');
// 目标文件夹(packages)
const mpui = path.join(__dirname, '../packages');
// 目标components(packages/components)
const targetDir = path.join(mpui, 'components');
// 根目录
const root = path.join(__dirname, '../');
// 文档源目录(/docs)
const docsDir = path.join(__dirname, '../docs');
// 文档目标目录(/packages/docs)
const docsTargetDir = path.join(mpui, 'docs');

module.exports = {
    packages,
    mpui,
    targetDir,
    root,
    docsDir,
    docsTargetDir,
};

2.复制项目的package.json

通过复制整个项目的packages.json到打包目录中,来减少手动复制造成的无用功及出错率。

以下是将项目的version赋值给打包目录中package.json的小操作。由于在后续我们更新npm时,version不能和上一次的重复,所以,version会是我们打包发布的频繁修改项,加入这个操作后,以后我们发布只需要修改最外层的version即可。其他package.json中的内容可根据项目需要进行复制。

build/updatePackage.js


const path = require('path');
const fs = require('fs-extra');

const {
    mpui,
    root,
} = require('./dirName');

function updatePackage () {
    // 打包目录的package.json
    const mpuiPackagePath = path.join(mpui, 'package.json');
    // 读取根节点package.json内容
    let mpuiData = fs.readFileSync(path.join(root, 'package.json'), 'utf-8');
    mpuiData = JSON.parse(mpuiData);
    // 读取打包目录的package.json内容
    let mpuiPackageData = fs.readFileSync(mpuiPackagePath, 'utf-8');
    // 转换成json
    mpuiPackageData = JSON.parse(mpuiPackageData);
    // 将version重新赋值
    mpuiPackageData.version = mpuiData.version;

    // 输出到打包目录的package.json
    fs.outputFileSync(mpuiPackagePath, JSON.stringify(mpuiPackageData, '', 4));
}

module.exports = updatePackage;

3.引入自动生成文档工具

  1. 安装依赖
yarn add shelljs @hjtvuese/cli -D
  1. 创建config文件

hjtvuese.config.js

module.exports = {
    title: 'mpui组件文档', // 生成组件文档index的title
    include: ['src/components/**/*.vue'], // 包含的文件
    exclude: [], // 排除的文件,node_modules已被默认排除
    outDir: './docs', // 文档的输出目录
}
  1. 添加scripts命令
"docs:gen": "hjtvuese gen",
  1. 生成文档拷贝脚本

build/createDocs.js

const fs = require('fs-extra');
const shell = require('shelljs');

const {
    docsDir,
    docsTargetDir,
} = require('./dirName');

function createDocs() {
    // 生成文档
    shell.exec('npm run docs:gen');
    
    // 清空已有文档
    const docExists = fs.existsSync(docsTargetDir)
    if (docExists) {
        fs.removeSync(docsTargetDir);
    }
    // 拷贝文档
    fs.copySync(docsDir, docsTargetDir);
}

module.exports = createDocs;

4.脚本主文件

把我们之前的小功能组装起来,形成最终执行的脚本文件

const fs = require('fs-extra');
const path = require('path');
const argv = process.argv.splice(2)[0]
const shell = require('shelljs');
const updatePackageJson = require('./updatePackage');
const createDocs = require('./createDocs');

const {
    packages,
    mpui,
    targetDir,
    root,
} = require('./dirName');

// 组装package.json
updatePackageJson();

// 拷贝README.md文件
fs.copySync(path.join(root, 'README.md'), path.join(mpui, 'README.md'));

// 生成文档
createDocs();

// 先清空packages/components文件夹
const exists = fs.existsSync(targetDir);
if (exists) {
    fs.removeSync(targetDir);
}

// 读取components文件夹,同步组件
const packagesLists = fs.readdirSync(packages);

packagesLists.reduce((promise, item) => {
    const comPath = path.join(packages); // components文件夹
    const componentsPath = path.join(comPath, item); // 组件文件
    fs.copySync(componentsPath, path.join(targetDir, item)); // 复制到package/targetDir中
    console.log(item + '组件同步成功');
    return promise;
}, Promise.resolve([])).then(() => {
    console.log('全部成功');
    if (argv === 'npm') {
        // 如果script命令参数是:npm走上传npm方法
        console.log('----- 开始上传 npm -----');
        start();
    }
});

// 上传npm
function start() {
    // cmd命令
    let cmdStr = 'npm publish --access public'; // 如果项目名是以@开头,要添加参数 --access public,不然npm会认为是私包,需要你充值付费才能上传
    // 先进入packages文件夹
    shell.cd('packages'); // 进入packages文件夹
    shell.exec(cmdStr); // 执行发布命令
}

整个流程:

  1. 把根目录的package.json某些内容复制到packages中的package.json中
  2. 把根目录的README.md拷贝到packages中
  3. 使用@hjtvuese/cli插件生成组件文档,放在根目录的docs中,再拷贝到packages中(也可以直接生成到packages中)
  4. 清空packages/components文件夹
  5. 从src/components中拷贝组件文件到packages/components中
  6. 发布上传npm

5.用命令调用

在scripts中加入命令

package.json

"cmp": "node build/build-cmp.js cmp",
"build:npm": "node build/build-cmp.js npm",

调用

npm run cmp 更新packages
npm run build:npm 更新packages并上传npm

todo

  • 项目工程化
  • 自动删除注释
  • 打包代码压缩
  • 单元测试

总结

开发组件并上传npm其实是非常容易的,本质就是弄一个packages文件夹,然后把组件放进去,进行npm发布即可。但是作为一名有追求的程序员,我们要把这个过程变得更加自动、智能,减少搬砖的工作,专注于主业务代码。

现在有了脚本,我们只需要维护好组件文件,README.md,还有版本号,其他工作就通过脚本来自动帮我们执行了,是不是很方面呢。

题外话:第一次写分享文章,经验不足,请大家多多担待。