关于前端:手握手教你搭建组件库环境

52次阅读

共计 17361 个字符,预计需要花费 44 分钟才能阅读完成。

Vue3.0曾经公布了很长一段时间了,最近也在想着怎么去做工程化的货色,于是就想本人弄一个组件库捎带深刻学习Vue3.0, 于是便有了明天的这篇文章。

Git 地址:https://github.com/ZhQuella/AzUIFront

技术栈

包管理工具:

yarn

开发模块:

Vite
Vue 3.0

打包工具:

Gulp
Rollup

单元测试:

Jest

语法工具:

ESLint

语言:

TypeScript

为什么要应用 Yarn

看到包管理工具应用的事 yarn 或者很多小伙伴不太能了解为什么要应用 yarn,说到这里可能就须要理解一下前端的工程化的概念了,什么是前端的工程化?工程化别离为 模块化 组件化 规范化 自动化

模块化

模块化 是指将一个文件拆分成多个相互依赖的文件,最初进行对立的打包和加载,这样可能很好的保障高效的多人合作。
JavaScript模块化:CommonJSAMDCMD以及 ES6 Module
CSS 模块化:SassLessStylusBEMCssModules等。其中预处理器和 BEM 都会有的一个问题就是款式笼罩。
资源模块化:任何资源都能以模块的模式进行加载,目前大部分我的项目中的文件、CSS、图片等都能间接通过 JS 做对立的依赖关系解决

组件化

不同于模块化,模块化是对文件、对代码和资源拆分,而组件化则是对 UI 层面 的拆分。
组件化并不是前端所特有的,一些其余的语言或者桌面程序等,都具备组件化的先例。确切的说,只有有 UI 层的展现,就必然有能够组件化的中央。简略来说,组件就是将一段 UI 款式和其对应的性能作为独立的整体去对待,无论这个整体放在哪里去应用,它都具备一样的性能和款式,从而实现复用,这种整体化的细想就是组件化。不难看出,组件化设计就是为了减少复用性,灵活性,进步零碎设计,从而进步开发效率。
组件零碎是一个重要概念,因为它是一种形象,容许咱们应用小型、独立和通常可复用的组件构建大型利用。咱们会须要对页面进行拆分,将其拆分成一个一个的整机,而后别离去实现这一个个整机,最初再进行组装。
组件化的形象设计是很重要的,不仅减少了复用性进步了工作效率,从某种程度上来说也反馈了程序员对业务和产品设计的了解,一旦有问题或者须要性能扩大时,你就会发现之前的设计是如许的有意义。

规范化

规范化指的是咱们在工程开发初期以及开发期间制订的系列标准,其中又蕴含了:

  1. 我的项目目录构造
  2. 对于编码这块的束缚,个别咱们都会采纳一些强制措施,比方 ESLintStyleLint 等。
  3. 联调标准
  4. 文件命名标准
  5. 款式治理标准:目前风行的款式治理有 BEMSassLessStylusCSS Modules 等形式
  6. 工作流:其中蕴含分支命名标准、代码合并标准等
  7. 定期代码审查

自动化

从最早先的 gruntgulp 等,再到目前的webpackparcel。这些自动化工具在自动化合并、构建、打包都能为咱们节俭很多工作。而这些只是前端自动化其中的一部分,前端自动化还蕴含了继续集成、自动化测试等方方面面。


想必大家对与工程化也有了肯定的理解,那么会过头来持续说为什么要应用 yarn,下面说到了 模块化 如果咱们想一下,组件的开发与组件文档的展现和组件库的自身是存在所有关联的,然而关联性并没有那么大,能够应用 yarn 的工作空间来分隔他们使他们本事作为一个独立的个体而存在,yarn工作流与 npm 相似都是应用 package.json 文件,yarn会重组 node_modules 文件,且不会与 npm 抵触。yarn的工作空间可能更好的帮忙咱们治理多个我的项目,能够在多个子项目中应用独立的 package.json 治理我的项目依赖。yarn会依据就依赖关系帮忙你剖析所有子项目的共用依赖,保障所有的我的项目专用的依赖只会被下载和装置一次。

初始化我的项目

初始化创立我的项目:

mkdir AzUiFont
cd AzUiFont
yarn init -y

创立.gitignore

node_modules
coverage
dist
es
lib

package-lock.json

批改 package.json

{
  "name": "az-ui-font",
  "private": true,
  "version": "0.0.1",
  "main": "index.js",
  "license": "MIT"
}

搭建初始目录构造:

├─packages          //  我的项目总目录
│  ├─azui               //  组件库目录
│  ├─docs               //  展现文档目录
│  └─play               //  组件库开发展现目录
├─script            //  运行脚本
├─.gitignore       
├─index.html       
├─package.json     
├─README.md        
└─tsconfig.json
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>AzUIFront</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

tsconfig.json

{
  "compilerOptions": {
    "rootDir": ".",
    "sourceMap": false,
    "target": "esnext",
    "module": "esnext",
    "jsx": "preserve",
    "moduleResolution": "node",
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": ".",
    "lib": ["esnext", "dom"],
    "types": ["jest", "node"]
  }
}

代码标准束缚

这里应用 eslint 对代码标准进行束缚,装置如下工具:

yarn add eslint -D -W
yarn add eslint-formatter-pretty -D -W
yarn add eslint-plugin-json -D -W
yarn add eslint-plugin-prettier -D -W
yarn add eslint-plugin-vue -D -W
yarn add @vue/eslint-config-prettier -D -W
yarn add babel-eslint -D -W
yarn add prettier -D -W

增加.eslintrc.js

module.exports = {
    "root": true,
    "env": {
        "browser": true,
        "es2020": true,
        "node": true,
        "jest": true
    },
    "globals": {
        "ga": true,
        "chrome": true,
        "__DEV__": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        'plugin:json/recommended',
        'plugin:vue/vue3-essential',
        '@vue/prettier'
    ],
    "parserOptions": {
        "ecmaVersion": 12,
        "parser": "@typescript-eslint/parser",
        "sourceType": "module"
    },
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    "rules": {}};

增加.eslintignore

*.sh
*.md
*.ico
*.css
*.md
*.scss
*.woff
*.ttf
*/*/shims.d.ts 
*/*/index.html
*/*/yarn-error.log
packages/azui/rollup-plugin-vue/index.d.ts
node_modules
lib
coverage
dist

package.json 增加如下命令:

package.json

{
  "scripts": {"lint": "eslint --no-error-on-unmatched-pattern --ext .vue --ext .ts --ext .tsx packages/**/ --fix"},
  "devDependencies": {
    "eslint": "^7.24.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-formatter-pretty": "^4.0.0",
    "eslint-plugin-jest": "^24.3.5",
    "eslint-plugin-json": "^2.1.2",
    "eslint-plugin-prettier": "^3.4.0",
    "prettier": "^2.2.1"
  }
}

代码束缚局部曾经解决实现,接下来解决组件局部

组件库局部

执行命令

cd .\packages\azui\
yarn init -y

package.json

{
  "name": "azui",
  "version": "0.0.1",
  "private": true,
  "license": "MIT"
}

目录构造如下

├─rollup-plugin-vue
└─src
    ├─packages
    │  └─Button
    │      ├─Button.vue
    │      ├─index.ts
    │      └─__tests__
    └─styles

集成 Babel 到我的项目中,须要装置如下依赖:

yarn add babel -D -W
yarn add babel-plugin-syntax-dynamic-import -D -W
yarn add babel-plugin-syntax-jsx -D -W
yarn add babel-preset-env -D -W
yarn add @babel/plugin-proposal-optional-chaining -D -W
yarn add @babel/preset-env -D -W
yarn add @vue/babel-plugin-jsx -D -W

增加.babelrc

{"presets": [["@babel/preset-env", { "targets": { "node": "current"} }]],
  "plugins": [
    "syntax-dynamic-import",
    ["@vue/babel-plugin-jsx"],
    "@babel/plugin-proposal-optional-chaining",
    "@babel/plugin-proposal-nullish-coalescing-operator"
  ],
  "env": {
    "utils": {
      "presets": [
        [
          "env",
          {
            "loose": true,
            "modules": "commonjs",
            "targets": {"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
            }
          }
        ]
      ],
      "plugins": [
        [
          "module-resolver",
          {"root": ["azui"],
            "alias": {"azui/src": "az-ui/lib"}
          }
        ]
      ]
    },
    "test": {"plugins": ["istanbul"],
      "presets": [["env", { "targets": { "node": "current"} }]]
    },
    "esm": {"presets": [["@babel/preset-env", { "modules": false}]]
    }
  }
}

集成自动化测试(单元测试)

yarn add jest -D -W
yarn add vue-jest@5.0.0-alpha.5 -D -W
yarn add babel-jest    -D -W                        
yarn add @vue/compiler-sfc@3.0.2 -D -W
yarn add @vue/test-utils@next -D -W
yarn add typescript -D -W

增加 jest.config.js

module.exports = {
  testEnvironment: "jsdom", // 默认 JSdom
  roots: ["<rootDir>/src/packages"], //
  transform: {
    "^.+\\.vue$": "vue-jest", // vue 单文件
    "^.+\\js$": "babel-jest", // esm 最新语法 import
  },
  moduleFileExtensions: ["vue", "js", "json", "jsx", "ts", "tsx", "node"],
  testMatch: ["**/__tests__/**/*.spec.js"],
  // 别名
  moduleNameMapper: {"^azui(.*)$": "<rootDir>$1",
    "^main(.*)$": "<rootDir>/src$1",
  },
};

package.json

{
  "scripts": {"test": "jest --runInBand"}
}

款式打包,增加如下依赖:

yarn add gulp -D -W
yarn add gulp-autoprefixer -D -W
yarn add gulp-sass -D -W
yarn add gulp-cssmin -D -W
yarn add cp-cli -D -W
yarn add tslib -D -W

package.json

{
  "scripts": {"build:theme": "gulp build --gulpfile gulpfile.js"}
}

应用 Rollup 打包组件,装置如下依赖:

yarn add rollup -D -W
yarn add rollup-plugin-peer-deps-external -D -W
yarn add rollup-plugin-scss -D -W
yarn add rollup-plugin-terser -D -W
yarn add rollup-plugin-vue -D -W
yarn add @rollup/plugin-node-resolve -D -W
yarn add @rollup/plugin-commonjs -D -W
yarn add @rollup/plugin-json -D -W
yarn add @rollup/plugin-replace -D -W
yarn add @rollup/plugin-babel -D -W
yarn add rollup-plugin-vue -D -W
yarn add rollup-plugin-typescript2 -D -W

增加 rollup.config.js

import path from "path";
import scss from "rollup-plugin-scss";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import replace from "@rollup/plugin-replace";
import babel from "@rollup/plugin-babel";
import {terser} from "rollup-plugin-terser";
import ts from "rollup-plugin-typescript2";

import pkg from "./package.json";

const vuePlugin = require("./rollup-plugin-vue/index");
const getPath = (_path) => path.resolve(__dirname, _path);

const name = "AzUi";

const createBanner = () => {
  return `/*!
  * ${pkg.name} v${pkg.version}
  * (c) ${new Date().getFullYear()} Aaron
  * @license MIT
  */`;
};

const extensions = [".js", ".ts", ".tsx", ".scss"];

const tsPlugin = ts({tsconfig: getPath("./tsconfig.json"),
  extensions,
});

const createBaseConfig = () => {
  return {
    input: "src/index.ts",
    external: ["vue"],
    plugins: [peerDepsExternal(),
      babel(),
      resolve({extensions,}),
      commonjs(),
      json(),
      tsPlugin,
      vuePlugin({css: true}),
      scss({
        output: process.env.NODE_ENV === 'development'?
                  './dist/lib/index.css':
                  false,
        watch: ["./src/styles"]
      })
    ],
    output: {
      sourcemap: false,
      banner: createBanner(),
      externalLiveBindings: false,
      globals: {vue: "Vue"}
    }
  };
};

function mergeConfig(baseConfig, configB) {const config = Object.assign({}, baseConfig);
  // plugin
  if (configB.plugins) {baseConfig.plugins.push(...configB.plugins);
  }

  // output
  config.output = Object.assign({}, baseConfig.output, configB.output);

  return config;
}

function createFileName(formatName) {return `dist/az-ui.${formatName}.js`;
}

// es-bundle
const esBundleConfig = {
  plugins: [
    replace({__DEV__: `(process.env.NODE_ENV !== 'production')`,
    }),
  ],
  output: {file: createFileName("esm-bundler"),
    format: "es",
  },
};

// es-browser
const esBrowserConfig = {
  plugins: [
    replace({__DEV__: true,}),
  ],
  output: {file: createFileName("esm-browser"),
    format: "es",
  },
};

// es-browser.prod
const esBrowserProdConfig = {
  plugins: [terser(),
    replace({__DEV__: false,}),
  ],
  output: {file: createFileName("esm-browser.prod"),
    format: "es",
  },
};

// cjs
const cjsConfig = {
  plugins: [
    replace({__DEV__: true,}),
  ],
  output: {file: createFileName("cjs"),
    format: "cjs",
  },
};
// cjs.prod
const cjsProdConfig = {
  plugins: [terser(),
    replace({__DEV__: false,}),
  ],
  output: {file: createFileName("cjs.prod"),
    format: "cjs",
  },
};

// global
const globalConfig = {
  plugins: [
    replace({
      __DEV__: true,
      "process.env.NODE_ENV": true,
    }),
  ],
  output: {file: createFileName("global"),
    format: "iife",
    name
  },
};
// global.prod
const globalProdConfig = {
  plugins: [terser(),
    replace({__DEV__: false,}),
  ],
  output: {file: createFileName("global.prod"),
    format: "iife",
    name
  },
};

const formatConfigs = [
  esBundleConfig,
  esBrowserProdConfig,
  esBrowserConfig,
  cjsConfig,
  cjsProdConfig,
  globalConfig,
  globalProdConfig,
];

function createPackageConfigs() {return formatConfigs.map((formatConfig) => {return mergeConfig(createBaseConfig(), formatConfig);
  });
}

export default createPackageConfigs();

package.json

{
  "scripts": {"build": "rollup -c"}
}

组件库局部曾经实现,接下来配置文档局部:

文档局部

执行命令

cd ../..
cd .\packages\docs\

创立目录构造:

├─public
├─scripts
└─src
    ├─assets
    ├─components
    └─__docs__

装置如下依赖:

yarn add @vitejs/plugin-vue -D -w
yarn add markdown-it-containe -D -w
yarn add node-sass -D -w
yarn add sass -D -w
yarn add sass-loader -D -w
yarn add vite -D -w
yarn add vite-plugin-vuedoc -D -w
yarn add vue@next -S -W
yarn add vue-router@4 -S -W

package.json

{
  "name": "@azui/docs",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "tsrv test"
  },
  "dependencies": {
    "azui": "0.0.1",
    "vue": "^3.0.7",
    "vue-router": "^4.0.4"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.1.5",
    "markdown-it-container": "^3.0.0",
    "node-sass": "^5.0.0",
    "sass": "^1.32.11",
    "sass-loader": "^11.0.1",
    "vite": "^2.0.5",
    "vite-plugin-vuedoc": "^3.1.2"
  }
}

增加 vite.config.ts

import {defineConfig} from "vite";

import {createPlugin, vueDocFiles} from "vite-plugin-vuedoc";
import markdownItContainer from "markdown-it-container";
import vue from "@vitejs/plugin-vue";

import vitePluginSyncmd from "./scripts/vitePluginSyncmd";

const containers = ["success", "warning", "info", "error"].map((type) => {
  return [
    markdownItContainer,
    type,
    {validate: function (params: string) {const str = params.trim();
        if (str === type || str.startsWith(`${type} `)) {return [str, str === type ? "" : str.substr(type.length + 1)];
        }
        return null;
      },
      render: function (tokens: any[], idx: number) {const str = tokens[idx].info.trim();
        const m = [str, str === type ? "" : str.substr(type.length + 1)];
        if (tokens[idx].nesting === 1) {
          // opening tag
          return `<p>${type}--${m[1]}`;
        } else {
          // closing tag
          return "</p>";
        }
      },
    },
  ];
});

export default defineConfig({
  server: {port: 3000,},
  assetsInclude: ["src/assets"],
  optimizeDeps: {exclude: ["azui"],
  },
  plugins: [vitePluginSyncmd(),
    createPlugin({
      markdownIt: {plugins: [...containers],
      },
      highlight: {theme: "one-dark",},
    }),
    vue({include: [...vueDocFiles],
    }),
  ],
});

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "lib": ["esnext", "dom"],
    "types": ["vite/client"],
    "baseUrl": "."
  },
  "include": ["./shims.d.ts", "src/**/*"],
  "exclude": ["node_modules", "dist"]
}

shims.d.ts

declare module '*.vue' {import type { DefineComponent} from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

declare module '*.md' {import { DefineComponent} from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/src/assets/icon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

scripts/vitePluginSyncmd.ts

import {Plugin} from "vite";
import chokidar from "chokidar";
import path from "path";
import fs from "fs-extra";

function docFileName(path: string) {const ret = path.split("/__docs__/");
  if (ret.length === 2) {return ret;}
  return [null, null];
}

function syncdocServer({root}) {const componentsDir = path.join(root, "../elenext/src/components");
  const docsPath = (file) => path.join(root, "src/__docs__", file);
  const watcher = chokidar.watch(`${componentsDir}/**/__docs__/*.md`);
  watcher
    .on("add", async (path) => {const [, file] = docFileName(path);
      if (file) {
        try {await fs.copy(path, docsPath(file));
        } catch (err) {console.error(err);
        }
      }
    })
    .on("change", async (path) => {const [, file] = docFileName(path);
      if (file) {
        try {await fs.copy(path, docsPath(file));
        } catch (err) {console.error(err);
        }
      }
    })
    .on("unlink", async (path) => {const [, file] = docFileName(path);
      if (file) {
        try {await fs.remove(docsPath(file));
        } catch (err) {console.error(err);
        }
      }
    });
}

function vitePluginSyncmd(): Plugin {
  return {
    name: "Syncmd",
    configureServer(server) {syncdocServer({ root: server.config.root});
    },
  };
}

export default vitePluginSyncmd;

src/__docs__/Button.zh-CN.md

---
title: Button
wrapperClass: md-button
---

# Button 按钮

罕用的操作按钮

## 按钮色彩

应用 `color` 属性来定义 Button 的色彩

`color`: 'primary' | 'success' | 'info' | 'warning' | 'danger'

## Button Props

| 参数        | 阐明           | 类型                                                             | 默认值 |
| ----------- | -------------- | ---------------------------------------------------------------- | ------ |
| color       | 类型           | 'primary' / 'success' / 'warning' / 'danger' / 'info' / 'string' | -      |

components/AppLayout.vue

<template>
  <div class="demo-layout">
    <div>
      <div class="demo-header">
        <div class="layout-center">
          <div align="middle">
            <div :flex="1">
              <Logo />
            </div>
            <div>
              <div mode="horizontal">
                <div>
                  <input v-model="data.primaryColor" />
                </div>
                <div>
                  <a href="https://github.com/JasKang/elenext" target="__blank">GitHub</a>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div>
        <div class="layout-center">
          <div align="top" :wrap="false">
            <div :flex="'200px'">
              <div style="padding-top: 40px">
                <div mode="vertical" :current-path="route.path">
                  <template v-for="menu in menus" :key="menu.title">
                    <div :title="menu.title">
                      <div v-for="item in menu.items" :key="item" :path="`/${item.name.toLowerCase()}`">
                        {{`${item.name}-Aaron` }}
                      </div>
                    </div>
                  </template>
                </div>
              </div>
            </div>
            <div :flex="1">
              <div class="site-content">
                <router-view />
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import {defineComponent, reactive} from 'vue'
import {useRoute} from 'vue-router'
import menus from '../menus'

export default defineComponent({
  name: 'AppLayout',
  setup() {const route = useRoute()


    const data = reactive({primaryColor: '#409eff',})

    return {
      route,
      menus,
      data,
    }
  },
})
</script>
<style lang="scss">
.demo-layout {height: 100vh;}
.layout-center {
  max-width: 1200px;
  width: 100vw;
  margin: 0 auto;
}
.site-content {
  width: 100%;
  padding: 20px;
  // max-width: 900px;
  margin: 0 auto;
}

.demo-aside {border-right: solid 1px #e6e6e6;}
.demo-header {
  border-bottom: solid 1px #e6e6e6;
  // box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>

App.vue

<template>
  <div class="box">111</div>
  <router-view />
</template>

<script lang="ts">
import {defineComponent} from 'vue'

export default defineComponent({
  name: 'App',
  components: {}})
</script>

main.ts

import 'vite-plugin-vuedoc/style.css';
import {createApp} from 'vue';

import AzUI from 'azui';
import 'azui/dist/lib/index.css';

import {router} from './router';
import App from './App.vue';

const app = createApp(App);

app.use(AzUI);
app.use(router);
app.mount('#app');

menus.ts

import {Component, defineAsyncComponent} from 'vue'
import Button from './__docs__/Button.zh-CN.md'

type MenuItemType = {
  name: string
  component: (() => Promise<Component>) | Component
}
type MenuType = {
  title: string
  items: MenuItemType[]}

export default [
  {
    title: 'Basic',
    items: [{ name: 'Button', component: Button},
    ]
  }
] as MenuType[]

router.ts

import {createRouter, createWebHistory, RouteRecordRaw} from 'vue-router'
import AppLayout from './components/AppLayout.vue'
import menus from './menus'

export const router = createRouter({history: createWebHistory(),
  strict: true,
  routes: [{ path: '/'},
    {
      path: '/component',
      name: 'Layout',
      component: AppLayout,
      redirect: '/button',
      children: menus.reduce((prev, item) => {
        const _routes = item.items.map(i => {console.log(i.component)
          return {path: `/${i.name.toLowerCase()}`,
            name: i.name,
            component: i.component,
          }
        })
        prev.push(..._routes)
        return prev
      }, [] as RouteRecordRaw[]),
    },
  ],
})

文档局部实现,接下来解决组件开发局部,其实组件开发局部能够和文档局部放在一起,应用不同的路由,然而两者的性能不雷同,所以独自配置了一个子项目。

开发局部

执行如下命令:

cd ../..
cd .\packages\play\

目录构造:

├─public
├─scripts
├─index.html

└─src
    ├─App.vue
    └─main.ts

package.json,相干依赖自行装置

{
  "name": "@azui/play",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "tsrv test"
  },
  "dependencies": {
    "azui": "0.0.1",
    "vue": "^3.0.7"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^1.1.5",
    "node-sass": "^5.0.0",
    "sass": "^1.32.11",
    "sass-loader": "^11.0.1",
    "vite": "^2.0.5"
  }
}

shims.d.ts

declare module '*.vue' {import type { DefineComponent} from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

declare module '*.md' {import { DefineComponent} from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "lib": ["esnext", "dom"],
    "types": ["vite/client"],
    "baseUrl": "."
  },
  "include": ["./shims.d.ts", "src/**/*"],
  "exclude": ["node_modules", "dist"]
}

vite.config.ts

import {defineConfig} from "vite";
import vue from "@vitejs/plugin-vue";


export default defineConfig({
  server: {port: 8080,},
  optimizeDeps: {exclude: ["azui"],
  },
  plugins: [vue()
  ]
});

这样的话组件开发局部也就配置好了,当初就是启动我的项目的时候,返回到根目录,在根目录的 package.json 中增加scripts:

我的项目启动

root package.json

{
  "scripts": {
    "dev": "yarn workspace azui run dev",
    "start": "yarn workspace @azui/docs run dev",
    "play": "yarn workspace @azui/play run dev",
    "test": "yarn workspace azui run test",
    "lint": "eslint --no-error-on-unmatched-pattern --ext .vue --ext .ts --ext .tsx packages/**/ --fix"
  }
}

须要留神的是,肯定要先运行 yarn dev 依据 dev 来运行打包出开发环境所须要的组件,之后再运行 start 或者 play,记的有两个命令行窗口运行哦,如果间接运行startplay会抛出谬误:

[plugin:vite:import-analysis] 
Failed to resolve entry for package "azui". 
The package may have incorrect main/module/exports specified in its package.json.

这是因为在我的项目中无奈找到所依赖的组件库~ 这一点须要非凡留神。

结束语

要搭建一个绝对欠缺的组件库,都是须要通过一系列我的项目的积淀的。目前而言,组件库的开发流程上仍然会存在一些问题,比方版本治理、降级回退等。工夫是最好的老师,置信在前面的迭代中,咱们仍然可能放弃初心与激情,积极探索与发现,构建出更加欠缺的前端工程体系。

正文完
 0