使用 grunt 调用 Vite Library 模式构建组件

解读

国内前端团队普遍已转向 Vite 作为新一代构建工具,但存量项目仍依赖 Grunt 做任务编排。面试官想验证两点:

  1. 你能否让“老”Grunt 无缝驱动“新”Vite,而不是推翻现有 CI 流程;
  2. 你是否理解 Vite Library 模式(即 vite build --mode lib)与常规应用构建的差异:入口为组件源码、输出格式为 es + umd、外部化 peerDependencies、生成 d.ts 与 sourcemap。
    回答时要体现“渐进升级”思路,既尊重 Grunt 插件体系,又发挥 Vite 的极速优势,避免“二选一”的极端答案。

知识点

  • grunt-contrib-clean:清理旧 dist,保证每次构建“零残留”。
  • grunt-run / grunt-exec:在 Grunt 任务里同步调用 npx vite build --config vite.lib.config.ts,捕获 exit code,失败即中断后续任务。
  • vite.lib.config.ts 关键配置:
    – build.lib.entry 指向组件入口(如 src/index.ts);
    – build.lib.name 暴露全局变量(供 umd 使用);
    – build.lib.fileName 返回带版本号的文件名,方便 Grunt 后续做 CDN 上传;
    – rollupOptions.external 把 react、vue 等 peerDependencies 外部化,减小包体;
    – plugins 数组加入 dts 插件自动生成类型声明。
  • grunt-contrib-copy:把 README、package.json 拷进 dist,方便发 npm 私库。
  • grunt-bump + grunt-conventional-changelog:在构建成功后自动抬升 package.json 版本并生成中文 ChangeLog,契合国内“版本号即发布”习惯。
  • grunt-contrib-zip:将 dist 打成 tgz,供内网 GitLab CI 做制品归档。
  • 错误码约定:Vite 返回非 0 时,Grunt 任务必须 failFatal,防止“带病”制品进入私服。
  • 并发安全:若多人同时发布,需在 Gruntfile 里用 grunt-lockfile 插件做分布式锁,避免版本号冲突。

答案

  1. 安装依赖
    npm i -D vite @vitejs/plugin-react rollup-plugin-dts grunt grunt-contrib-clean grunt-run grunt-contrib-copy grunt-bump grunt-conventional-changelog grunt-contrib-zip

  2. 在项目根新建 vite.lib.config.ts

    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    import dts from 'rollup-plugin-dts';
    import { resolve } from 'path';
    
    export default defineConfig({
      plugins: [react(), dts({ insertTypesEntry: true })],
      build: {
        lib: {
          entry: resolve(__dirname, 'src/index.tsx'),
          name: 'MyUI',
          fileName: (format) => `my-ui.${format}.js`
        },
        rollupOptions: {
          external: ['react', 'react-dom'],
          output: {
            globals: { react: 'React', 'react-dom': 'ReactDOM' }
          }
        },
        sourcemap: true,
        emptyOutDir: true
      }
    });
    
  3. 编写 Gruntfile.js(CommonJS 写法,兼容老 Node 版本)

    module.exports = function (grunt) {
      grunt.initConfig({
        clean: { dist: 'dist' },
        run: {
          viteLib: {
            cmd: 'npx',
            args: ['vite', 'build', '--config', 'vite.lib.config.ts'],
            options: { failOnError: true, stderr: true }
          }
        },
        copy: {
          meta: {
            files: [
              { src: 'README.md', dest: 'dist/README.md' },
              { src: 'package.json', dest: 'dist/package.json' }
            ]
          }
        },
        bump: {
          options: {
            files: ['package.json'],
            commit: false,
            createTag: false,
            push: false
          }
        },
        changelog: {
          options: {
            preset: 'conventionalcommits',
            releaseCount: 1,
            file: 'dist/CHANGELOG.md'
          }
        },
        compress: {
          dist: {
            options: { archive: 'release/my-ui-v<%= pkg.version %>.tgz', mode: 'tgz' },
            expand: true,
            cwd: 'dist/',
            src: ['**']
          }
        }
      });
    
      grunt.loadNpmTasks('grunt-contrib-clean');
      grunt.loadNpmTasks('grunt-run');
      grunt.loadNpmTasks('grunt-contrib-copy');
      grunt.loadNpmTasks('grunt-bump');
      grunt.loadNpmTasks('grunt-conventional-changelog');
      grunt.loadNpmTasks('grunt-contrib-compress');
    
      grunt.registerTask('build:lib', [
        'clean',
        'run:viteLib',
        'copy:meta',
        'bump',
        'changelog',
        'compress'
      ]);
    };
    
  4. 在 CI(如 GitLab Runner)里执行
    npm run grunt build:lib
    成功后 dist/ 即为可直接发布到 内网 Verdaccio 的目录,release/*.tgz 为归档制品。

拓展思考

  • 双轨构建:若仓库同时维护 legacy 页面(requirejs)与新组件库,可在 Gruntfile 里加条件判断:当存在 vite.lib.config.ts 时走 Vite,否则回退到 grunt-contrib-uglify + grunt-browserify,实现“同一代码库,两套出口”。
  • 微前端场景:把 Vite 构建的 es 格式产物作为 联邦模块 上传到 qiankun 主应用,Grunt 任务里增加一步“生成 importmap.json”,让主应用运行时动态映射版本,避免手动改 HTML。
  • 性能优化:当组件库体积过大,可在 Grunt 任务链中插入 rollup-plugin-visualizer,生成 stats.html 并自动推送到企业微信机器人,提醒开发者及时拆分懒加载子包。
  • 合规审计:国内金融客户要求“构建过程可回溯”,可在 Grunt 任务里用 grunt-git-info 把当前 commit、构建人、构建机 IP 写入 dist/buildinfo.json,方便审计追踪。