Vue多组件仓库开发与发布

在开发组件时,咱们可能会指望一类组件放在同一个代码仓库下,就像element那样,咱们可使用element提供的脚手架,也可使用vue cli 3建立一个更‘新’的项目。javascript

项目建立

经过vue cli 3建立项目,建立文件夹packages用于存放组件。html

单个组件目录

packages下就是每个组件,每一个组件和单独项目同样,会有package.jsonREADME.mdsrcdist等文件及目录。vue

如何演示/调试组件

在组件开发过称中,咱们须要对组件进行展现,因此建立了examples文件夹,用于存放每一个组件示例。
经过一个列表展现出全部的组件,点击选择当前开发的组件,进入对应的example
路由的根就是一个导航列表,而后每一个组件对应一个路由,经过一个配置文件的components.js来生成这个路由。java

// 路由
import Navigation from "./Navigation";
import components from "./components";

let routes = components.map(component => ({
  path: `/${component.name}`,
  component: () => import(`../examples/${component.name}`)
}));

routes.unshift({
  path: "",
  component: Navigation
});

export default routes;
复制代码

自动化脚本

建立/编译/发布

建立新的组件,须要修改components.js配置文件,在examplespackages下建立对应目录。
编译/发布组件,由于仓库下会有多个组件,若是一次发布多个,就须要进入每一个文件夹下执行命令。
上面过程实现自动化,有不少种方式,好比能够经过npm run <script>,能够直接经过node命令等。这里我参考element,采用了Makefile。node

建立script文件夹,其中包括建立脚本new.js和构建脚本build.jsnpm

建立脚本

建立脚本主要就是目录的建立与文件的写入,其中可能须要注意的可能就是格式问题。
一种方式是在``之间,按照规范格式去完成写入内容,这样作比较麻烦,并且可能面临格式化要求修改问题。
另外一种方式是在脚本中引入eslint,脚本中的eslint.CLIEngine能够根据配置文件(好比.eslintrc.js)格式化文件。须要注意的是须要比命令行中配置须要多添加fix: true配置, 以下json

const CLIEngine = eslint.CLIEngine;
const cli = new CLIEngine({ ...require("../.eslintrc.js"), fix: true });
复制代码

eslint在脚本中的使用方法,更具体的能够参考eslint文档中Node.js API部分api

// scripts/new.js部分
...

components.push({
  label: newName,
  name: newName
})

const updateConfig = function(path, components) {
  writeFile(path, `module.exports = ${JSON.stringify(components)}`).then(() => {
    console.log("完成components.js")
    // 格式化
    CLIEngine.outputFixes(cli.executeOnFiles([configPath]))
  })
}

const createPackages = function(componentName) {
  try {
    const dir = path.resolve(__dirname, `../packages/${componentName}/`)
    // 建立文件夹
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir)
      console.log(`完成建立packages/${componentName}文件夹`)
    }
    // 写入README
    if (!fs.existsSync(`${dir}/README.md`)) {
      writeFile(
        `${dir}/README.md`,
        `## ${componentName} ### 使用说明 `
      ).then(() => {
        console.log("完成建立README")
      })
    }
    // 写入package.json
    if (!fs.existsSync(`${dir}/package.json`)) {
      writeFile(
        `${dir}/package.json`,
        `{ "name": "@hy/${componentName}", "version": "1.0.0", "description": "${componentName}", "main": "./dist/hy-${componentName}.umd.min.js", "keywords": [ "${componentName}", "vue" ], "author": "", "license": "ISC" } `
      ).then(() => {
        console.log("完成建立package.json")
      })
    }
    // 建立index.js
    if (!fs.existsSync(`${dir}/index.js`)) {
      writeFile(`${dir}/index.js`, `export {}`).then(() => {
        console.log("完成建立index.js")
        CLIEngine.outputFixes(cli.executeOnFiles([`${dir}/index.js`]))
      })
    }
  } catch (err) {
    console.error(err)
  }
}

const createExample = function(componentName) {
  try {
    const dir = path.resolve(__dirname, `../examples/${componentName}/`)
    // 建立文件夹
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir)
      console.log(`完成建立examples/${componentName}文件夹`)
    }
    // 写入index.vue
    if (!fs.existsSync(`${dir}/index.vue`)) {
      writeFile(
        `${dir}/index.vue`,
        `<template> </template> <script> import { } from '../../packages/${componentName}/index' export default { components: {} } </script> `
      ).then(() => {
        console.log(`完成建立examples/${componentName}/index.vue文件`)
        // 格式化index.vue
        CLIEngine.outputFixes(cli.executeOnFiles([`${dir}/index.vue`]))
      })
    }
  } catch (err) {
    console.error(err)
  }
}

...
复制代码

构建脚本

// build.js
...

async function build() {
  for (let i = 0, len = components.length; i < len; i++) {
    const name = components[i].name
    await buildService.run(
      "build",
      {
        _: ["build", `${root}/packages/${name}/src/index.js`],
        target: "lib",
        name: `hy-${name}`,
        dest: `${root}/packages/${name}/dist`,
        // 生成格式: umd格式会同时成功demo.html commonjs,umd,umd-min
        formats: "commonjs,umd-min"
        // clean: false
      },
      ["--target=all", `./packages/${name}/src/index.js`]
    )
  }
}

...
复制代码

Lerna

lerna是一个多包仓库管理的工具,能够帮助建立、管理、发布多包仓库中的包。
关于lerna我也没有太深刻得使用,只是用到了发布。首先在项目下执行init初始化了项目,在每次commit以后,能够执行publishlerna会对应代码库打tag,并发布到npm仓库。并发

项目版本问题

0.0.1为不规范版本号,最小应该从1.0.0开始。npm publish没法发布,可是lerna publish能够发布。
致使结果安装为固定版本号,而不是以^开头的版本号范围。outdate能够检测到有更新,没法经过update升级。async

组件开发

组件开发主要是在packages/<component name>/src目录下进行,在example/<component name>/目录下能够引入该组件src下的源文件,用一些数据来进行开发测试。组件开发和项目中的组件开发基本相同。
做为组件库中的组件,须要更多的考虑其通用性和易用性。不能为了通用而加入不少的属性,而使其失去易用性;一样也不能为了易用,而使其过于简单,使用范围过于局限。
对于每个属性、每一个抛出去的方法,都须要认真考虑其必要性。

惟一不一样的地方可能须要注意的是导出的方式。
一种是直接导出组件,这种形式在使用时须要引入,而且在components中声明,也就是局部注册。
另外一种是添加install方法后导出。这种形式须要调用vue.use方法,至关于全局注册。

相关文章
相关标签/搜索