pnpm init @vitejs/app + 项目名
pnpm i vue-router@4
import { createRouter, createWebHistory } from "vue-router";
const routes = [
{
path: "/",
redirect: "/home",
},
{
path: "/home",
name: "home",
component: () => import("../view/home/index.vue"),
meta: {
title: "home",
},
},
];
export default createRouter({
history: createWebHistory(),
routes,
scrollBehavior() {
// 始终滚动到顶部
return { top: 0 };
},
});
在main.ts里导入,使得整个应用支持路由。
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
const app = createApp(App);
app.use(router);
app.mount("#app");
<script setup lang="ts">script>
<template><router-view>router-view>template>
<style>
#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>
项目跑起来以后,进行Web Component组件封装
src下新建文件夹lib,新建button组件,封装组件所用语法与Vue2/3常用语法一致,这里使用的是vue3.x+ts
lib>demo>demo.vue
<template>
<div class="demoValue">{{ demoValue }}</div>
<div class="button" @click="clickHandler">+</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
const demoValue = ref<number>(0);
const clickHandler = () => {
demoValue.value += 1;
};
</script>
<style scoped lang="less">
.demoValue {
color: royalblue;
font-size: 100px;
}
.button {
width: 100px;
height: 30px;
border: 1px solid pink;
border-radius: 5px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
</style>
导入到home页面展示效果
组件可用开始导出工作,将组件样式单独新建一个css文件剪切出来。
.demoValue {
color: royalblue;
font-size: 100px;
}
.button {
width: 100px;
height: 30px;
border: 1px solid pink;
border-radius: 5px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
demo组件新建index.ts,新建一个CustomElement。
import { defineCustomElement } from "vue"
import Demo from "./demo.vue";
import demoStyle from './demo.css'
export default defineCustomElement({...Demo, styles: [
demoStyle
]})
lib根目录下新建index.ts ,进行相关组件配置
lib>index.ts
import { App } from "vue";
import ComDemo from "./demo";
const components = [ComDemo];
// 导出普通vue组件
export { ComDemo };
// 注册普通VUE组件
export function registerComUIVue3(app: App): void {
for (const component of components) {
app.component(component.name, component);
}
}
// 注册跨技术栈组件
export function registerComUI(): void {
customElements.define("com-demo", ComDemo);
}
export default registerComUI;
需安装rollup,node版本需在12.x以上
为了方便使用,这里将rollup打包出口文件配置在了dist目录中,先需使用vite进行打包后,方可使用rollup打包组件,rollup配置参考官网。
npm run build
rollup -c
import esbuild from "rollup-plugin-esbuild";
import vue from "rollup-plugin-vue";
import scss from "rollup-plugin-scss";
import dartSass from "sass";
import { terser } from "rollup-plugin-terser";
import alias from "@rollup/plugin-alias";
import path from "path";
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import json from "@rollup/plugin-json";
import styles from "rollup-plugin-styles";
export default {
input: "src/lib/index.ts",
output: [
{
globals: {
vue: "Vue",
},
name: "boriska-ui",
file: "dist/lib/boriska-ui.js",
format: "umd",
plugins: [terser()],
},
{
name: "boriska-ui",
file: "dist/lib/boriska-ui.esm.js",
format: "es",
plugins: [terser()],
},
],
plugins: [
json(),
resolve({
browser: true,
preferBuiltins: true,
}),
commonjs(),
scss({ include: /\.scss$/, sass: dartSass }),
styles({
mode: "extract",
}),
esbuild({
include: /\.[jt]s$/,
minify: process.env.NODE_ENV === "production",
target: "es2015",
}),
vue({
include: /\.vue$/,
}),
alias({
entries: [
{
find: "@", // 别名名称,作为依赖项目需要使用项目名
replacement: path.resolve(__dirname, "src"),
customResolver: resolve({
extensions: [".js", ".jsx", ".vue", ".sass", ".scss"],
}),
},
],
}),
],
};
{
"name": "boriskaui",
"version": "0.2.0",
"license": "MIT",
"author": "sxzq",
"files": [
"dist/lib/*"
],
"main": "dist/lib/boriska-ui.esm.js",
"module": "dist/lib/boriska-ui.esm.js",
"scripts": {
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview",
"prepare": "husky install"
},
"dependencies": {
"@vitejs/plugin-vue-jsx": "^1.3.4",
"@vue/babel-preset-jsx": "^1.2.4",
"axios": "^0.21.4",
"crypto-js": "^4.1.1",
"github-markdown-css": "^5.1.0",
"less": "^4.1.3",
"path": "^0.12.7",
"prismjs": "^1.26.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-jsx": "^1.0.3",
"rollup-plugin-typescript2": "^0.31.2",
"vite-plugin-markdown": "^2.0.2",
"vue": "^3.2.25",
"vue-router": "4"
},
"devDependencies": {
"@commitlint/cli": "^16.2.1",
"@commitlint/config-conventional": "^16.2.1",
"@rollup/plugin-alias": "^3.1.9",
"@rollup/plugin-json": "^4.1.0",
"@vicons/antd": "^0.11.0",
"@vicons/carbon": "^0.11.0",
"@vicons/fa": "^0.11.0",
"@vicons/fluent": "^0.11.0",
"@vicons/ionicons4": "^0.11.0",
"@vicons/ionicons5": "^0.11.0",
"@vicons/material": "^0.11.0",
"@vicons/tabler": "^0.11.0",
"@vicons/utils": "^0.1.4",
"@vitejs/plugin-vue": "^2.0.1",
"cross-env": "^7.0.3",
"husky": "^7.0.4",
"marked": "^4.0.9",
"mockjs": "^1.1.0",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-esbuild": "^4.8.2",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-scss": "^3.0.0",
"rollup-plugin-styles": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-vue": "^6.0.0",
"sass": "^1.47.0",
"vite": "^2.7.2",
"vite-plugin-mock": "^2.9.6"
}
}
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// 将所有包含短横线的标签作为自定义元素处理
isCustomElement: (tag) => tag.startsWith("jw-"),
},
},
}),
],
});
vite.config.ts同样需要添加web component配置。
plugins: [
vue({
template: {
compilerOptions: {
// 将所有包含短横线的标签作为自定义元素处理
isCustomElement: (tag) => tag.includes("jw-"),
},
},
}),
visualizer(),
],
复制该文件到vue的组件库中。导入到页面文件中,组件的命名需与到出的文件名保持一致。自定义标签的前缀,需要与vite中的配置对应。
isCustomElement: (tag) => tag.includes("jw-"),
import { useState } from 'react'
import logo from './logo.svg'
import './App.css'
import { ComDemo } from "./Comui/boriska-ui.esm.js";
function App() {
const [count, setCount] = useState(0)
const initHandler = async () => {
const res = await customElements.get("JwButton");
return res;
};
initHandler().then((res: any) => {
customElements.define("jw-button", ComDemo);
});
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Hello Vite + React!</p>
<jw-button />
</header>
</div>
)
}
export default App
封装组件时,不管有没有参数,都要声明defineProps。
const props = defineProps({
size: {
type: [String, Number],
default: 10,
},
});
否则打包后引用组件时会报错
"skipLibCheck": true,