参考 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的文件夹。
- 在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"
],
}
- 将
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.引入自动生成文档工具
- 安装依赖
yarn add shelljs @hjtvuese/cli -D
- shelljs: 执行shell命令
- @hjtvuese/cli:根据注释自动生成vue组件文档
- 创建config文件
hjtvuese.config.js
module.exports = {
title: 'mpui组件文档', // 生成组件文档index的title
include: ['src/components/**/*.vue'], // 包含的文件
exclude: [], // 排除的文件,node_modules已被默认排除
outDir: './docs', // 文档的输出目录
}
- 添加scripts命令
"docs:gen": "hjtvuese gen",
- 生成文档拷贝脚本
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); // 执行发布命令
}
整个流程:
- 把根目录的package.json某些内容复制到packages中的package.json中
- 把根目录的README.md拷贝到packages中
- 使用@hjtvuese/cli插件生成组件文档,放在根目录的docs中,再拷贝到packages中(也可以直接生成到packages中)
- 清空packages/components文件夹
- 从src/components中拷贝组件文件到packages/components中
- 发布上传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,还有版本号,其他工作就通过脚本来自动帮我们执行了,是不是很方面呢。
题外话:第一次写分享文章,经验不足,请大家多多担待。