vite + gulp 写一个组件库框架
上源码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import jsx from "@vitejs/plugin-vue-jsx"
import dts from 'vite-plugin-dts'
import { resolve } from "path";
import viteScssPlugin from './vite-my-scss-plugin'
export default defineConfig({
plugins: [
// 自己写的scss插件用来处理 scss 样式的引用,针对 按需引入导致的问题
viteScssPlugin(),
vue(),
jsx(),
dts({
outDir: ['types'],
// 将动态引入转换为静态(例如:`import('vue').DefineComponent` 转换为 `import { DefineComponent } from 'vue'`)
staticImport: true,
// 将所有的类型合并到一个文件中
rollupTypes: true
}),
],
build: {
cssCodeSplit: false,
lib: {
// 库模式 指向 库的入口文件
entry: resolve(__dirname, "src/index.ts"),
// 因为在 rollupOptions 中定义了output ,在这失效了
name: "SjComponentLib",
fileName: (format) => `sj-component-lib.${format}.js`,
},
rollupOptions: {
external: ["vue", /\.scss/, /\.css/], // 不处理 scss和css 因为在gulp处理过了
output: [
{
// 打包格式
format: "es",
//打包后文件名
entryFileNames: "[name].mjs",
//让打包目录和我们目录对应
preserveModules: true,
exports: "named",
//配置打包根目录
dir: "es",
},
{
//打包格式
format: "cjs",
//打包后文件名
entryFileNames: "[name].js",
//让打包目录和我们目录对应
preserveModules: true,
// 对应的打包根节点
preserveModulesRoot: 'src',
exports: "named",
//配置打包根目录
dir: "lib",
},
],
},
minify: "terser", // 压缩模式
},
resolve: {
alias: {
// 配置路径别名
'@': resolve(__dirname, 'src')
},
extensions: ['.vue', '.js', '.ts', '.jsx', '.tsx', '.json'] // 可以忽略 后缀名
},
})
gulp 源码
// index.js
import gulp from 'gulp'
import { resolve,dirname } from 'path'
import { fileURLToPath } from 'url'
import dartSass from 'sass'
import gulpSass from 'gulp-sass'
import autoprefixer from 'gulp-autoprefixer'
import shell from 'shelljs'
import cleanCSS from 'gulp-clean-css';
const componentPath = resolve(dirname(fileURLToPath(import.meta.url)), '../')
const { src, dest } = gulp
const sass = gulpSass(dartSass)
// 删除打包产物
export const removeDist = async () => {
shell.rm('-rf', `${componentPath}/lib`)
shell.rm('-rf', `${componentPath}/es`)
shell.rm('-rf', `${componentPath}/types`)
}
// 构建css
export const buildRootStyle = () => {
return src(`${componentPath}/src/index.scss`)
.pipe(sass()) // 处理sass 其实也就是编译成了css
.pipe(cleanCSS()) // 压缩css
.pipe(
autoprefixer({
overrideBrowserslist: ["> 1%", "last 2 versions"], // 兼容
cascade: false, // 是否美化属性值
})
)
.pipe(dest(`${componentPath}/es`)) // 输出
.pipe(dest(`${componentPath}/lib`))// 输出
}
// 构建每个组件下单独的css
export const buildStyle = () => {
return src(`${componentPath}/src/**/style/**.scss`)
.pipe(sass())
.pipe(cleanCSS())
.pipe(
autoprefixer()
)
.pipe(dest(`${componentPath}/es`))
.pipe(dest(`${componentPath}/lib`))
}
// 打包组件
export const buildComponent = async () => {
shell.cd(componentPath)
shell.exec('vite build') // 执行vite构建
}
// series串行任务 ,还有个并行任务在这暂时没用,可todo
export default series(
removeDist,
buildComponent,
buildStyle,
buildRootStyle,
)
上面解决了css的分离问题,但是 在tsx 中 引入的scss 会被编译替换为空 所以在这我写了一个插件,将 scss 替换成 css 这样打包后 就可以直接执行了
import fs from 'fs';
export default () => {
return {
name: "vite-my-plugin",
async config(config: any, env: any) {
console.error('config')
await clear()
await writeLog('config:' + JSON.stringify(config))
await writeLog('config:' + JSON.stringify(env))
return config
},
async transform(source: string, id: any) {
if (process.env.NODE_ENV === 'production' && process.versions.node) {
if (id.endsWith('.tsx')||id.endsWith('/src/index.ts')) {
// 假设我们想要在每个 .js 文件的开头添加一行 console.log
// const originalCode = fs.readFileSync(id).toString()/* 获取原始代码的代码 */; // 注意:这里需要实际获取源代码的逻辑
console.error('transform', id)
source = source.replace("index.scss", "index.css");
await writeLog('source:' + JSON.stringify(source))
}
}
return source
},
}
}
pnpm + Monorepo 简单实践
项目根目录下,创建一个
pnpm-workspace.yaml
packages:
- "packages/**"
在顶层引入 @sj/components-lib 库的名字 ,然后 pnpm install
package.json
"dependencies": {
"@sj/components-lib": "workspace:*",
},
外面项目 import SjComponents from '@sj/components-lib' 就能使用 底层的 组件了