vite打包业务组件库遇到的问题

192 阅读4分钟

vite对应的配置文件vite.config.js
vite默认的配置文件是vite.config.js,也可以通过--config命令行选项指定一个配置文件:vite --config my-config.js

antd中的组件库如何打包?如何实现按需加载? mp.weixin.qq.com/s/5KAAYdgaf…

1.vite如何区分开发 && 生产环境

方法一:通过在script命令指定run serve和run build对应的配置文件。

  "scripts": {
    "dev": "vite --config ./config/vite.config.dev.ts",
    "build": "vue-tsc --noEmit && vite build --config ./config/vite.config.prod.ts",
    "report": "cross-env REPORT=true npm run build",
    "preview": "npm run build && vite preview --host",
  },

参考文献:www.jianshu.com/p/c9c52b24c…

方法二:vite提供defineConfig工具函数,这工具函数可以接受一个函数参数,函数参数是一个对象(对象中的相关属性提供环境判断)

export default defineConfig(({ command, mode, isSsrBuild, isPreview }) => {
  if (command === 'serve') { // 如果是开发环境command是serve
    return {
      console.log('开发模式配置');
    }
  } else { // 如果是生产环境command是build
    // command === 'build'
    return {
       console.log('生产模式配置');
    }
  }
})

2.如何打包出CJS、UMD、ESModule格式

2.1 CJS、UMD、ESModule的区别

2.2 为什么要打包成这三种格式

2.3 在vite中配置 CJS/UMD/ESM 三种格式

3.如何实现按需加载

3.0 为什么要按需加载

3.1 实现按需加载的几种方式

(1) antd中如何实现按需加载

(2) Monore中按需加载

juejin.cn/post/715608…

www.bytezonex.com/archives/lo…

2.2 库模式打包 && package.json配置

(1) vite-config.js 中的 build.lib字段
import { defineConfig } from 'vite'
import path from 'path'
export default defineConfig({
  build: {
    lib: {
      entry: path.resolve(__dirname, 'lib/main.js'),
      // umd 形式的命名空间
      name: 'MyLib',
      fileName: (format) => `my-lib.${format}.js`
    },
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ['vue'],
      output: {
        // 在 umd 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: 'Vue'
        }
      }
    }
  }
})

(2) package.json中对CJS/UMD/ESM格式引入的配置

对于组件库加载不同格式的打包文件的引入和导出

main、module注册:不同模块化格式的引入是不同的,如果是require引入则从main字段获取打包文件,如果是import的话则是从module中获取。

  • main - 表示commonjs文件入口
  • module - 表示es文件入口
  • types - 表示typescript文件入口

注:
在开发阶段的文件入口是module(开发阶段使用的是esModule) 在上线阶段的文件入口默认是main字段

export导出:如果配置./dist/,说明导出的文件是放在dist目录下,如果是“.”的话则放在服务器的根目录下。

vite常见配置

{
  name: "my-lib", // 包名
  // 代表只上传 dist 目录和 package.json 文件,如果不写则默认上传所有非 node_modules 文件
  files: ["dist"],
  // 声明包内导出的内容,该字段是一个较新的语法,建议能写就写,但是相应的兼容写法都需要写上。
  exports: {
    // . 代表该包只导出在了第一级,只能使用 import xx from 'my-lib'的方式引入包内容,不能使用 import xxx from 'my-lib/dist/my-lib.es.js'等方式引入
    ".": {
      "import": "./dist/my-lib.es.js", // 通过 import 引入时会匹配到这里   
      "require": "./dist/my-lib.umd.js", // 通过 require 引入时会匹配到这里
      "types": "./dist/my-lib.d.ts" // ts 定义文件
    },
    // 代表导出了'my-lib/dist'目录下所有内容,可以 import xx from 'my-lib/dist/my-lib.es.js' 引入包内容
    "./dist/*": {
      "import": "./dist/my-lib.es.js",
      "require": "./dist/my-lib.umd.js",
      "types": "./dist/my-lib.d.ts"
    }
  },
  // 通过 require 引入时会匹配到这里,exports 的兼容写法
  main: "./dist/my-lib.umd.js",
  // 通过 import 引入时会匹配到这里,exports 的兼容写法
  module: "./dist/my-lib.es.js",
  // ts 定义文件,exports 的兼容写法
  types: "./dist/my-lib.d.ts"
}

后期优化:巧用 exports 和 typeVersions 提升 npm 包用户使用体验zhuanlan.zhihu.com/p/627434408

import { defineConfig } from 'vite';  
import vue from '@vitejs/plugin-vue';  
import AutoImport from 'unplugin-auto-import/vite';  
import Components from 'unplugin-vue-components/vite';  
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';  
import path from 'path';  
  
export default defineConfig({  
  root: process.cwd(),
  base: './',  // 项目部署的基础路径
  publicDir: 'public', // 静态资源服务的文件夹 类型 string | false
  logLevel: 'info', // 调整控制台输出的级别 'info' | 'warn' | 'error' | 'silent'
  clearScreen: false, // 设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息
  plugins: [  
    vue(),  
    AutoImport({  
      imports: ['vue', 'vue-router'], // 自动导入 Vue 和 Vue Router 的相关函数  
    }),  
    Components({  
      resolvers: [ElementPlusResolver({
        importStyle: 'sass',
        // directives: true,
        // version: "",
        })], // 自动导入 Element Plus 组件  
    }),  
  ],  
  resolve: {  
    alias: {  
      '@': path.resolve(__dirname, './src'),  
    },  
  },  
  css: {  
    preprocessorOptions: {  
      scss: {  
        additionalData: `@import "./src/styles/variables.scss";`, // 全局样式变量  
      },  
    },  
  },  
  build: {  
    outDir: 'dist',  
    assetsDir: 'assets',  
    minify: 'terser', // 使用 terser 进行代码压缩  
    terserOptions: {  
      compress: {  
        drop_console: true, // 移除 console  
        drop_debugger: true, // 移除 debugger  
      },  
      output: {  
        comments: false, // 移除注释  
      },  
    },  
    sourcemap: false,  
  },  
  server: {  
    open: true,  
    port: 3000,  
    proxy: {
      "/api": {
        target: "http://localhost:8000",
        changeOrigin: false,
        rewrite: (path) => path.replace(/^\/api/, ''), // 重写路径
      },
    },  
  },  
});