乐趣区

关于vue3:手把手创建Vue3组件库

动机

当市面上支流的组件库不能满足咱们业务需要的时候,那么咱们就有必要开发一套属于本人团队的组件库。

环境

开发环境:

  • vue 3.0
  • vue/cli 4.5.13
  • nodeJs 12.16.3
  • npm 6.14.4

步骤

创立我的项目

应用 vue-cli 创立一个 vue3 我的项目,假如我的项目名为 custom-npm-ui

$ vue create custom-npm-ui

手动抉择设置。

布局目录

├─ build         // 打包脚本,用于寄存打包配置文件
│  ├─ rollup.config.js    
├─ examples      // 原 src 目录,改成 examples 用于示例展现
│  ├─ App.vue
│  ├─ main.ts
├─ packages      // 新增 packages 目录,用于编写寄存组件,如 button
│  ├─ SubmitForm
│  │  ├─ src/
│  │  ├─ index.ts
│  ├─ index.ts
├─ typings      // 新增 typings 目录,用于寄存 .d.ts 文件,把 shims-vue.d.ts 挪动到这里
│  ├─ shims-vue.d.ts
├─ .npmignore    // 新增 .npmignore 配置文件
├─ vue.config.js // 新增 vue.config.js 配置文件

src 目录改为 examples,并将外面的 assetscomponents 目录删除,移除 App.vue 里的组件援用。

我的项目配置

vue.config.js

新增 vue.config.js 配置文件,适配从新布局后的我的项目目录:

// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path')

module.exports = {
  // 批改 pages 入口
  pages: {
    index: {
      entry: "examples/main.ts", // 入口
      template: "public/index.html", // 模板
      filename: "index.html" // 输入文件
    }
  },
  // 扩大 webpack 配置
  chainWebpack: (config) => {
    // 新增一个 ~ 指向 packages 目录, 不便示例代码中应用
    config.resolve.alias
      .set('~', path.resolve('packages'))
  }
}

.npmignore

新增 .npmignore 配置文件,组件公布到 npm中,只有编译后的公布目录(例如 lib)、package.jsonREADME.md 才是须要被公布的,所以咱们须要设置疏忽目录和文件

# 疏忽目录
.idea
.vscode
build/
docs/
examples/
packages/
public/
node_modules/
typings/

# 疏忽指定文件
babel.config.js
tsconfig.json
tslint.json
vue.config.js
.gitignore
.browserslistrc
*.map

或者配置pkg#files:

  "files": [
    "lib/",
    "package.json",
    "README.md"
  ],

装置依赖后的目录构造:

└─custom-npm-ui
        │  package.json
        │  README.md
        └─lib
                index.css
                index.esm.js
                index.min.js

tsconfig.json

批改 tsconfig.json 中 paths 的门路

"paths": {
  "@/*": ["src/*"]
}

改为

    "paths": {
      "~/*": ["packages/*"]
    }

Notes:typescript反对的别名。

批改 include 的门路

  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ]

改为

  "include": [
    "examples/**/*.ts",
    "examples/**/*.tsx",
    "examples/**/*.vue",
    "packages/**/*.ts",
    "packages/**/*.tsx",
    "packages/**/*.vue",
    "typings/**/*.ts",
    "typings/shims-vue.d.ts",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ]

package.json

批改 package.json 中公布到 npm 的字段

  • name:包名,该名字是惟一的。可在 npm 近程源搜寻名字,如果存在则需换个名字。
  • version:版本号,每次公布至 npm 须要批改版本号,不能和历史版本号雷同。
  • description:形容。
  • main:入口文件,该字段需指向咱们最终编译后的包文件。
  • typings:types 文件,TS 组件须要。
  • keyword:关键字,以空格拆散心愿用户最终搜寻的词。
  • author:作者信息
  • private:是否公有,须要批改为 false 能力公布到 npm
  • license:开源协定

参考设置:

{
  "name": "custom-npm-ui",
  "version": "0.1.0",
  "private": false,
  "description": "基于 ElementPlus 二次开发的前端组件库",
  "main": "lib/index.min.js",
  "module": "lib/index.esm.js",
  "typings": "lib/index.d.ts",
  "keyword": "vue3 element-plus",
  "license": "MIT",
  "author": {
    "name": "yourname",
    "email": "youremail@163.com"
  }
 }

在 package.json 的 scripts 新增编译和公布的命令

"scripts": {
    "build": "yarn build:clean && yarn build:lib && yarn build:esm-bundle && rimraf lib/demo.html",
    "build:clean": "rimraf lib",
    "build:lib": "vue-cli-service build --target lib --name index --dest lib packages/index.ts",
    "build:esm-bundle": "rollup --config ./build/rollup.config.js"
}

其中 build:lib 是利用 vue-cli 进行 umd 形式打包,build:esm-bundle 是利用 rollup 进行 es 形式打包。

build:lib具体参数解析如下:

  • --target: 构建指标,默认为利用模式。改为 lib 启用库模式。
  • --name: 输入文件名
  • --dest : 输入目录,默认 dist。改成 lib
  • [entry]: 入口文件门路,默认为 src/App.vue。这里咱们指定编译 packages/ 组件库目录。

build:esm-bundle打包后的资源在 webpack2+rollup 环境中可通过 pkg#module 配置载入应用。

rollup.config.js

新增 build/rollup.config.jsrollup 打包脚本:

import cjs from "@rollup/plugin-commonjs"; // commonjs 转 es module —— rollup 只反对 es module
import resolve from "@rollup/plugin-node-resolve"; // 搭配 @rollup/plugin-commonjs 应用
// import ts from '@rollup/plugin-typescript' //【报错】应用 ts 报错
import typescript from "rollup-plugin-typescript2"; // 解析 TS 语法
import vue from "rollup-plugin-vue"; // 解析 vue
import babel from "@rollup/plugin-babel";
import scss from "rollup-plugin-scss"; // 解析 scss
// import requireContext from "rollup-plugin-require-context"; //【不可用】反对 webpack 的 require.context API —— 须要装置 npm install --save-dev generate-source-map@0.0.5
import {writeFileSync, existsSync, mkdirSync} from "fs";

const extensions = [".js", ".ts", ".vue"];
export default {
  input: "packages/index.ts",
  output: [
    {
      file: "lib/index.esm.js", // 多文件输入的话,须要应用 dir 代替 file
      format: "es",
      globals: {vue: "Vue", // 通知 rollup 全局变量 Vue 即是 vue},
    },
  ],
  extensions,
  plugins: [ // 程序很重要
    scss({output: function (styles, styleNodes) {if (!existsSync("lib/")) {mkdirSync("lib/");
        }
        writeFileSync("lib/index.css", styles);
      },
    }),
    vue({compileTemplate: true,}),
    // requireContext(),
    resolve({
      jsnext: true,
      main: true,
      browser: true,
      extensions,
    }),
    cjs(),
    typescript(),
    babel({}),
  ],
  external: ["vue", "element-plus"],
};

开发组件

注意事项

  • 组件内不能应用懒加载
  • 组件不能应用 require.context() 对立治理
  • 不反对 JSX 语法编写模版 —— 更好的抉择React

依赖装置

环境依赖

$ npm i -D rimraf rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-typescript2 rollup-plugin-vue @rollup/plugin-babel rollup-plugin-scss

开发依赖

$ npm i -D element-plus@1.0.2-beta.69 babel-plugin-import

配置.babel.config.js

module.exports = {presets: ["@vue/cli-plugin-babel/preset"],
  plugins: [
    [
      "import",
      {libraryName: "element-plus",},
    ],
  ],
};

更新examples/main.ts

import {createApp} from "vue";
import App from "./App.vue";
import "element-plus/lib/theme-chalk/index.css";

createApp(App).mount("#app");

编写组件

在 packages 目录下新建 index.ts 文件和 SubmitForm/ 文件夹,在 SubmitForm 下新建 index.tssrc/index.vue,构造如下:

.
├── SubmitForm
│   ├── SubmitForm.stories.ts
│   ├── index.ts
│   └── src
│       ├── FormRender.vue
│       ├── fileds
│       │   ├── Color.vue
│       │   ├── Datetime.vue
│       │   ├── Radio.vue
│       │   ├── Select.vue
│       │   ├── Switch.vue
│       │   ├── Text.vue
│       │   ├── Upload.vue
│       │   ├── hooks
│       │   │   └── useValueHandleHook.ts
│       │   └── index.ts
│       ├── index.vue
│       ├── schemas
│       │   ├── baseSchema.ts
│       │   └── schemasProp.ts
│       └── store
│           └── index.ts
├── common
│   └── getType.ts
└── index.ts

packages/SubmitForm/src/index.vue

<script lang="ts">
import {computed, defineComponent} from "vue";
import {ElForm} from "element-plus";
import {FormPropsType} from "./schemas/schemasProp";
import FormRender from "./FormRender.vue";
import {values, updateValues} from "./store";

export default defineComponent({
  name: "SubmitForm",
  props: FormPropsType,
  emits: ["runtimeChange"],
  components: {
    "el-form": ElForm,
    FormRender,
  },
  setup(props, { emit}) {const schemasCpt = computed(() => props.schema);
    const defaultValueCpt = computed(() => props.defaultValue);
    function handleRuntimeChange(name: string, value: any) {updateValues(name, value);
      emit("runtimeChange", name, value);
    }
    return {
      schemasCpt,
      defaultValueCpt,
      values,
      handleRuntimeChange,
    };
  },
});
</script>
<template>
  <el-form label-width="100px" :model="values">
    <template v-for="(schema, idx) of schemasCpt" :key="idx">
      <FormRender
        :schema="schema"
        :defaultValue="defaultValueCpt"
        v-bind="$attrs"
        :onRuntimeChange="handleRuntimeChange"
      />
    </template>
  </el-form>
</template>

packages/SubmitForm/index.ts,独自组件的入口文件,在其余我的项目能够应用 import {SubmitForm } from ‘custom-npm-ui’ 形式进行单个组件援用

import type {App} from "vue";
import SubmitForm from "./src/index.vue";
// 定义 install 办法,接管 Vue 作为参数。如果应用 use 注册插件,那么所有的组件都会被注册
SubmitForm.install = function (Vue: App) {
  // 遍历注册全局组件
  Vue.component(SubmitForm.name, SubmitForm);
};
export default SubmitForm;

packages/index.ts 作为组件库的入口文件,能够在其余我的项目的 main.ts 引入整个组件库,内容如下

import type {App} from "vue";
import SubmitForm from "./SubmitForm";

const components = [SubmitForm];
// 定义 install 办法,接管 Vue 作为参数。如果应用 use 注册插件,那么所有的组件都会被注册
const install = function (Vue: App): void {
  // 遍历注册全局组件
  components.map((component) => Vue.component(component.name, component));
};
export {
  // 以下是具体的组件列表
  SubmitForm,
};
export default {// 导出的对象必须具备 install,能力被 Vue.use() 办法装置
  install,
};

这样,咱们就实现一个简略的 SubmitForm 组件,后续须要扩大其余组件,依照 SubmitForm 的构造进行开发,并且在 index.ts 文件中 components 组件列表增加即可。

编写示例调试

examples/main.ts

import {createApp} from "vue";
import App from "./App.vue";
import CustomeUI from "~/index";
import "element-plus/lib/theme-chalk/index.css";

createApp(App).use(CustomeUI).mount("#app");

examples/App.vue 删除我的项目初始化的 HelloWorld 组件

<script lang="ts">
import {defineComponent, reactive, ref, toRaw} from "vue";
import formSchema from "./layouts/case.layout";

export default defineComponent({
  name: "App",
  components: {},
  setup() {const submitFormRef = ref();
    const schema = reactive(formSchema);
    const defaultValues = reactive({});
    function formRuntimeChange(name: string, value: any) {console.log(name, "=", value);
    }
    function submit() {console.log(submitFormRef.value.values);
    }
    return {
      submitFormRef,
      schema,
      defaultValues,
      formRuntimeChange,
      submit,
    };
  },
});
</script>
<template>
  <submit-form
    ref="submitFormRef"
    :schema="schema"
    :defaultValue="defaultValues"
    @runtimeChange="formRuntimeChange"
  >
  </submit-form>
  <button @click="submit"> 保留 </button>
</template>

<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

启动我的项目,测试一下

$ npm run serve

组件开发实现后,执行编译库命令:

$ npm run build

引入打包后的文件回归测试一下,没有问题再公布到 npm 仓库。

在示例入口 main.ts 援用咱们的组件库:

import {createApp} from "vue";
import App from "./App.vue";
import CustomeUI from "../lib/index.esm.js";
import "element-plus/lib/theme-chalk/index.css";

createApp(App).use(CustomeUI).mount("#app");

编写申明文件

创立目录构造

.
├── typings
│   ├── index.d.ts
│   ├── component.d.ts
│   └── packages
│       └── submit-form.vue.d.ts
├── common
│   └── getType.ts
└── index.ts

更新 package.json 配置

// package.json
{
  ...
  "typings": "./typings/index.d.ts",
  "files": [
    "lib/",
    "package.json",
    "typings/"
  ],
  "publishConfig": {"registry": "https://abc.com/"}
}

外围文件

// typings/index.d.ts
import type {App} from "vue";
export * from "./component.d";

export declare const install: (app: App, opt: any) => void;

declare const _default: {install: (app: App<any>, opt: any) => void;
};
export default _default;
// typings/component.d.ts
export {default as SubmitForm} from "./packages/submit-form.d";
// typings/packages/submit-form.d.ts
import {
  DefineComponent,
  ComponentOptionsMixin,
  VNodeProps,
  AllowedComponentProps,
  ComponentCustomProps,
  EmitsOptions,
  ComputedGetter,
  WritableComputedOptions,
} from "vue";
import {FormRowType} from "../schemas/schemasProp";

declare const _default: DefineComponent<
  Record<string, unknown>,
  {
    refName: string;
    schema: FormRowType[];
    defaultValue: Record<string, any>;
  },
  Record<string, unknown>,
  Record<string, ComputedGetter<any> | WritableComputedOptions<any>>, // computed
  Record<string, () => void>, // methods
  ComponentOptionsMixin,
  ComponentOptionsMixin,
  EmitsOptions,
  string,
  VNodeProps & AllowedComponentProps & ComponentCustomProps,
  Readonly<Record<string, unknown> & Record<string, unknown>>,
  Record<string, unknown>
>;
export default _default;

公布组件

配置 NPM 仓库地址

组件开发并测试通过后,就能够公布到 npm 仓库提供给其余我的项目应用了,首先编写 .npmrc 文件配置要上传的源地址:

registry=https://abc.com

更举荐更新 pkg#publishConfig 指定仓库地址:

  "publishConfig": {"registry": "https://abc.com"},

Notes:应用 .npmrc 配置 NPM 仓库地址,nrm无奈切换源。

获取 NPM 账号、明码

在 npm 官网注册即可

登录 npm 账号

在我的项目中 terminal 命令窗口登录 npm 账号

$ npm login
Username:
Password:
Email:(this IS public)

输出在 npm 的账号、明码、邮箱

公布

$ npm publish

组件文档

创立 Storybook 敌对型环境

在我的项目中 terminal 命令窗口执行命令:

$ npx -p @storybook/cli sb init

storybook是一个能够辅助 UI 开发的工具,是一个 UI 组件的开发环境。

sb init 初始化过程中,storybook会查看现有我的项目的dependencies,而后根据我的项目的现有框架,提供最佳的组装形式。

Storybook初始化做了以下步骤:

  • 装置 Storybook 须要的依赖
  • 更新pkg#run-script
  • 减少预设的配置文件

    • .storybook/main.js
    • .storybook/preview.js
  • 减少示例模版stories/

更新package.json

...
  "scripts": {
    "storybook": "start-storybook -p 6006 -h 0.0.0.0", // 启动本地服务以预览
    "build-storybook": "build-storybook"  // 构建
  },
...
$ npm run storybook # 启动本地服务拜访 storybook 我的项目

更新目录构造

├─ .storybook         // 预设的配置文件
│  ├─ main.js    // 入口文件
│  ├─ preview.js // 管制 Stories 的出现、全局资源的加载
├─ stories      // 示例模版
main.js
module.exports = {
  "stories": [  // Storybook 会抓取、载入配置门路下的指定文件渲染展现
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [  // Storybook 所用插件 —— Storybook 性能加强
    "@storybook/addon-links",
    "@storybook/addon-essentials"
  ],
  "framework": "@storybook/vue3" // Storybook 所用框架 —— Vue 环境反对
}

编写示例

入口配置

更新.storybook/main.js

module.exports = {
  "stories": [  // Storybook 会抓取、载入配置门路下的指定文件渲染展现
    "../packages/**/*.stories.@(js|jsx|ts|tsx)",
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  ...
}

组件 Story 编写

import SubmitForm from "./index"; // 引入组件
import {SchemaType, RuleTrigger} from "./src/schemas/baseSchema";

const caseSchema = [ // 示例数据
  {
    key: "moduleName",
    name: "title",
    type: SchemaType.Text,
    label: "栏目名称",
    placeholder: "请输出栏目名称",
    attrs: {//},
    rules: [
      {
        required: true,
        message: "栏目名称必填~",
        trigger: RuleTrigger.Blur,
      },
    ],
  },
  ...
];

export default {
  title: "ui 组件 /SubmitForm", // 展现题目:应用门路定义命名空间 —— 分组、分类
  component: SubmitForm,
};

const Template = (args: any) => ({ // 渲染组件
  components: {SubmitForm},
  setup() {
    return {...args,};
  },
  template: '<submit-form :schema="schema"></submit-form>',
});

export const 根本利用 = Template.bind({}); // 组件利用示例

(根本利用 as any).args = {
  schema: caseSchema,
  ref: "submitFormRef",
};

能够应用 props&computed 去承接 args 这样更合乎 Vue3 的书写格局:

// 后续的补充内容,和此处上下文无关。const Template = (args: any) => ({props: Object.keys(args),
  components: {SubmitForm, ElButton},
  setup(props) {const refName = computed(() => props.refName)
    const submitFormRef = ref();
    function submit() {console.log(submitFormRef.value.values);
    }
    function onRuntimeChange(name: string, value: any) {console.log(name, "=", value);
    }
    return {
      submit,
      onRuntimeChange,
      [refName.value]: submitFormRef,
      ...props,
    };
  },
  template: `
      <submit-form :schema="schema" :ref="refName" @runtimeChange="onRuntimeChange"></submit-form>
      <el-button @click="submit"> 提交 </el-button>
    `,
});

全局依赖配置

因为示例代码中依赖 element-plus,通过上述展示的页面没有款式,所以,StoryBook 渲染须要额定引入 element-plus 主题:

// preview.js
import "element-plus/lib/theme-chalk/index.css";

export const parameters = {actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {color: /(background|color)$/i,
      date: /Date$/,
    },
  }
}

启动本地服务

更新命令脚本
  // package.json
  "scripts": {
    "storybook": "start-storybook -p 6006 -h 0.0.0.0",
    "build-storybook": "build-storybook"
  },

-h 0.0.0.0以反对局域网拜访。

执行命令
$ npm run storybook
成果展现

Stories 中应用第三方 UI 库

ElementPlus 为例:

全局配置

如果 babel.config 没有配置按需加载,可间接编辑.storybook/preview.js

// .storybook/preview.js
import elementPlus from 'element-plus';
import {app} from '@storybook/vue3'

app.use(elementPlus);
export const decorators = [(story) => ({components: { story, elementPlus},
    template: '<elementPlus><story/></elementPlus>'
  })
];
import "element-plus/lib/theme-chalk/index.css";

export const parameters = {actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {color: /(background|color)$/i,
      date: /Date$/,
    },
  }
}

Notes:配置按需加载后,import elementPlus from 'element-plus';导入 elementPlus 报错:elementPlus is not defined —— 全局加载、按需加载不能在同一我的项目中应用。

按需加载

在须要应用 ElementPlusStories中间接引入即可:

// packages/SubmitForm/SubmitForm.stories.ts
import {ElButton} from 'element-plus';
import SubmitForm from "./index";
import {SchemaType, RuleTrigger} from "./src/schemas/baseSchema";

const caseSchema = [
  {
    key: "moduleName",
    name: "title",
    type: SchemaType.Text,
    label: "栏目名称",
    placeholder: "请输出栏目名称",
    attrs: {//},
    rules: [
      {
        required: true,
        message: "栏目名称必填~",
        trigger: RuleTrigger.Blur,
      },
    ],
  },
  ...
];

export default {
  title: "ui 组件 /SubmitForm",
  component: SubmitForm,
};

const Template = (args: any) => ({components: { SubmitForm, ElButton},
  setup() {
    return {...args,};
  },
  template: '<submit-form :schema="schema"ref="submitFormRef"></submit-form><el-button @click="submit"> 提交 </el-button>',
});
export const 根本利用 = Template.bind({});
(根本利用 as any).args = {schema: caseSchema,};
示例代码增加交互
// packages/SubmitForm/SubmitForm.stories.ts
import {ElButton} from "element-plus";
import {ref} from "vue";
import SubmitForm from "./index";
import {SchemaType, RuleTrigger} from "./src/schemas/baseSchema";

const caseSchema = [
  {
    key: "moduleName",
    name: "title",
    type: SchemaType.Text,
    label: "栏目名称",
    placeholder: "请输出栏目名称",
    attrs: {//},
    rules: [
      {
        required: true,
        message: "栏目名称必填~",
        trigger: RuleTrigger.Blur,
      },
    ],
  },
  ...
];

export default {
  title: "ui 组件 /SubmitForm",
  component: SubmitForm,
};
const Template = (args: any) => ({components: { SubmitForm, ElButton},
  setup() {const { refName} = args;
    const submitFormRef = ref();
    function submit() {console.log(submitFormRef.value.values);
    }
    function onRuntimeChange(name: string, value: any) {console.log(name, "=", value);
    }
    return {
      submit,
      onRuntimeChange,
      [refName]: submitFormRef,
      ...args,
    };
  },
  template: `
      <submit-form :schema="schema" :ref="refName" @runtimeChange="onRuntimeChange"></submit-form>
      <el-button @click="submit"> 提交 </el-button>
    `,
});
export const 根本利用 = Template.bind({});

(根本利用 as any).args = {
  refName: "submitFormRef",
  schema: caseSchema,
};

这里做了两件事:

  • 减少提交按钮
  • 减少数据提交交互

配置参数详情

默认文档展现

默认查看到的文档参数是以下样子:

参数配置

通过配置 argTypes 能够补充参数信息:

// packages/SubmitForm/SubmitForm.stories.ts
...
export default {
  title: "ui 组件 /SubmitForm",
  component: SubmitForm,
  argTypes: {
    refName: {
      description: '表单组件援用',
      type: {required: true,},
      table: {
        defaultValue: {summary: 'defaultNameRef',}
      },
      control: {type: 'text'}
    },
    schema: {
      type: {required: true,},
      table: {
        type: {
          summary: '渲染表单所需 JSON 构造',
          detail: 'JSON 构造蕴含表单渲染、交互所须要的必要字段,也蕴含表单的校验规定',
        },
        defaultValue: {summary: '[]',
          detail: `[
              {
                key: "moduleName",
                name: "title",
                type: SchemaType.Text,
                label: "栏目名称",
                placeholder: "请输出栏目名称",
                attrs: {//},
                rules: [
                  {
                    required: true,
                    message: "栏目名称必填~",
                    trigger: RuleTrigger.Blur,
                  },
                ],
              }
            ]
          `
        }
      }
    },
    runtimeChange: {
      description: '实时监听表单的更新',
      table: {category: 'Events',},
    }
  }
};
...

具体配置见链接。

现实成果

文档部署

执行命令:

$ npm run build-storybook

生成动态页面,间接部署动态页面即可。

目录构造:

│  0.0a0da810.iframe.bundle.js
│  0.0a0da810.iframe.bundle.js.LICENSE.txt
│  0.0a0da810.iframe.bundle.js.map
│  0.799c368cbe88266827ba.manager.bundle.js
│  1.9ebd2fb519f6726108de.manager.bundle.js
│  1.9face5ef.iframe.bundle.js
│  1.9face5ef.iframe.bundle.js.LICENSE.txt
│  1.9face5ef.iframe.bundle.js.map
│  10.07ff4e93.iframe.bundle.js
│  10.a85ea1a67689be8e19ff.manager.bundle.js
│  11.f4e922583ae35da460f3.manager.bundle.js
│  11.f4e922583ae35da460f3.manager.bundle.js.LICENSE.txt
│  12.1415460941f0bdcb8fa8.manager.bundle.js
│  2.8a28fd4e.iframe.bundle.js
│  2.8a28fd4e.iframe.bundle.js.LICENSE.txt
│  2.8a28fd4e.iframe.bundle.js.map
│  3.50826d47.iframe.bundle.js
│  4.779a6efa.iframe.bundle.js
│  5.f459d151315e6780c20f.manager.bundle.js
│  5.f459d151315e6780c20f.manager.bundle.js.LICENSE.txt
│  6.3bd64d820f3745f262ff.manager.bundle.js
│  7.3d04765dbf3f1dcd706c.manager.bundle.js
│  8.b541eadfcb9164835dfc.manager.bundle.js
│  8.c6cb825f.iframe.bundle.js
│  9.411ac8e451bbb10926c7.manager.bundle.js
│  9.51f84f13.iframe.bundle.js
│  9.51f84f13.iframe.bundle.js.LICENSE.txt
│  9.51f84f13.iframe.bundle.js.map
│  favicon.ico
│  iframe.html
│  index.html // 入口页面
│  main.4c3140a78c06c6b39fba.manager.bundle.js
│  main.e86e1837.iframe.bundle.js
│  runtime~main.1e621db5.iframe.bundle.js
│  runtime~main.91a0c7330ab317d35c4a.manager.bundle.js
│  vendors~main.0d1916dd840230bedd21.manager.bundle.js
│  vendors~main.0d1916dd840230bedd21.manager.bundle.js.LICENSE.txt
│  vendors~main.8b18b60f.iframe.bundle.js
│  vendors~main.8b18b60f.iframe.bundle.js.LICENSE.txt
│  vendors~main.8b18b60f.iframe.bundle.js.map
│
└─static
    └─media
            element-icons.5bba4d97.ttf
            element-icons.dcdb1ef8.woff

参考文档

  • Storybook 官网

参考文章很多,如狐疑内容参考,请分割,会思考减少到参考文档中

退出移动版