600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > vite + vue3 + storybook + ts 搭建组件库记录

vite + vue3 + storybook + ts 搭建组件库记录

时间:2021-11-08 14:10:24

相关推荐

vite + vue3 + storybook + ts 搭建组件库记录

目标

只按需引入,不依赖babel-import-plugin 插件。第三方依赖都不打包。用原生fetch请求数据。仅支持esmodule。配置package.json type:"module"

搭建

根据storybook 官网文档,需要在已有的项目中运行

npx storybook@latest init

也就是事先需要通过vite创建一个项目。

npm create vite@latest

之后再运行storybook 的命令,storybook会自动分析使用的构建工具,安装好需要的依赖,并自动新增文件。

storybook 增加了/src/stories目录,用于存放组件。

默认情况下,/src/stories 中放着 .vue, .stories, .css 文件,由于我希望把组件源代码单独放在一个文件夹下

目录预设

因此在项目根目录增加 /packages 目录,下面存放以组件名称命名的文件夹。以每个文件夹为单位表示为一个组件。

/src/stories 中.stories 文件引用/packages 目录下的.vue 用于生成storybook演示文档。

对于vite 的普通打包模式下,入口必须为index.html,因此需要使用vite 支持的lib模式打包。

lib模式下,对于图片等静态资源,处理为base64内联到代码中。且不支持配置。

base64的问题在于增大js体积,且不利于相同图片的复用。这块待研究。

构建vue组件

直接使用vite build 命令,会使用项目根目录下的vite.config.js 对指定的入口进行构建。构建产物默认输出到dist目录下。

lib模式下,构建产物有

index.jsstyle.css

对于一个vue组件来说,这种格式正式我想要的。

而/package 目录下面会有好多组件,因此需要借助vite 的JavsScript API 进行循环

vite JS API构建 /packages 目录

根据官网描述,使用下面js代码,可以通过js启动vite 打包。

import { build } from 'vite';build({//... vite config})

这里的 build() 方法传入的config对象,会和项目下的 vite.config.js 合并

所以将一些公共的配置可以写在 vite.config.js下

vite.config.js

import { defineConfig } from 'vite';import vue from '@vitejs/plugin-vue';import vueJsx from '@vitejs/plugin-vue-jsx';import dts from 'vite-plugin-dts';// https://vitejs.dev/config/export default defineConfig({build: {rollupOptions: {external: ['vue'], // 排除三方包},},plugins: [vue(),vueJsx(),dts({outputDir: './lib',entryRoot: './packages',}),],});

build.js 主要的构建方法

/*** 构建一个组件* @param {string} compName 组件名称,对应packages目录下的文件夹名称*/async function buildAComponent(compName) {const entry = path.join(packagesDir, compName, 'index.ts');const out = path.join(outDir, compName);await build({build: {outDir: out,lib: {entry: [entry],formats: ['es'],},},});}

这个是构建一个组件的方法,因此,我只要通过node 的 fs 模块读取并分析/packages 路径下的文件夹,遍历出来构建即可。

build.js代码

import { readdirSync, writeFileSync } from 'fs';import path, { dirname } from 'path';import { fileURLToPath } from 'url';import { build } from 'vite';const __dirname = dirname(fileURLToPath(import.meta.url));const packagesDir = path.join(__dirname, './packages');const outDir = path.join(__dirname, './lib');async function main() {const packages = readdirSync(packagesDir);let indexFileContent = '';const exportNames = [];const promise = [];for (const folderName of packages) {// const stats = lstatSync(path.join(packagesDir, compName));// if (stats.isDirectory()) {// // 如果是目录,则构建// }const firstLetter = folderName[0];const isFirstLetterUpperCase = /[A-Z]/.test(firstLetter);if (isFirstLetterUpperCase && folderName.indexOf('.ts') === -1) {promise.push(buildAComponent(folderName));indexFileContent += `import { ${folderName} } from './${folderName}/index.js';\n`;exportNames.push(folderName);}}await Promise.all(promise);indexFileContent += `export { ${exportNames.join(', ')} };`;writeFileSync(path.join(outDir, 'index.js'), indexFileContent);console.log('created: lib/index.js');}main();/*** 构建一个组件* @param {string} compName 组件名称,对应packages目录下的文件夹名称*/async function buildAComponent(compName) {const entry = path.join(packagesDir, compName, 'index.ts');const out = path.join(outDir, compName);await build({build: {outDir: out,lib: {entry: [entry],formats: ['es'],},},});}

main 函数中判断文件夹名称前面是大写字母开头的才当作组件来处理。

构建结果

/package/Button index.tsstyle.lessButton.vue

这一个目录入口为index.ts 构建完成后,输出到lib

/lib/Button index.jsstyle.css

至此,主要构建完成了

库入口

由于一个npm库需要有一个默认的入口js,因此需要在/lib 目录下面增加一个index.js 用于导入lib 下面所有组件,并导出。这部分代码在上面build.js中已经体现。

/lib/index.js

export { Button } from './Button/index.ts';

package.json 增加配置

{"main": "lib/index.js","module": "lib/index.js","files": ["lib","packages"],//...}

d.ts生成

使用vite-plugin-dts 插件

import dts from 'vite-plugin-dts';// ... plugins:[// vue(),// vueJsx(),dts({outputDir: './lib',entryRoot: './packages',}),]

构建dts速度有点慢 。

这样配置,会在lib/Button/ 下面增加d.ts 文件了。

与库的默认入口文件一样,需要指定默认declare 文件,package.json types 指定为 /packages/main.ts。(这里暂时指定.ts 文件,可能在一些构建工具中不识别,因为那些工具只识别d.ts 文件)

实现自动引入

一个组件默认的构建结果为index.js, style.css

鉴于使用的情况下引入 import { Button } from 'xxx'; 之外还要 import 'xxx/lib/Button/style.css';

使用babel-import-plugin 可以解决按需引入样式问题。

由于我的目标是不使用babel-import-pluing 因此,完成这个效果,只需要在/lib/Button/index.js 文件的最上方引入/lib/Button/style.css即可。

方案

使用node fs读写文件。借助vite plugin

使用vite plugin 实现

因为不想用node

由于vite基于rollup,根据rollup 官网文档,我们可以在插件的generateBundle钩子中在生成产物前操作文件内容。

代码

/*** 在产物js上导入css*/function () {return {name: 'auto-import-style',generateBundle(options, bundle) {bundle['index.js'].code = 'import "./style.css";\n' + bundle['index.js'].code;},};},

npm上也有类似的插件vite-plugin-libcss

构建vue组件要点

不能将vue依赖打包进代码中,否则会导致组件无法使用。

打包组件的产物js中,最上方应该为 import {} from 'vue'; 这样的代码。

通过配置vite.config.js 下的rollupOptions.external即可:

build: {rollupOptions: {external: ['vue'], // output: {// globals: {//vue: 'Vue', // umd需要// },// },},},

这里注释掉rollupOptions.output.globals 原因是默认构建lib会输入umd 和 es 模块的文件。我构建时会指定 build.lib.formats: ['es'] 就不需要了。

增量构建方案预设

由于现在我看使用vite-plugin-dts 生成d.ts 文件使用的时间过长。先制定一下增量构建的方案。

鉴于在正常开发过程中,始终用master分支作为正式分支。

因此在开发分支中,可以借助git 来对比当前开发分支与master分支的区别

使用node 的child_process 执行命令

git diff HEAD master --stat

可检查当前分支,对比master,哪些文件有变化。

得到控制台输出后,分析产物,确定package.json 中哪些组件有变动。以此仅构建变更过的组件。

vite可能会覆盖lib目录。构建前先保存一版lib目录?还是有官方配置。暂不研究。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。