vite + gulp 组件库框架

147 阅读2分钟

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' 就能使用 底层的 组件了