Bootstrap

vite完整配置项

/**
 * import.meta.env.VITE_x 在.env[mode]中定义的变量不能访问到要用 loadEnv函数代替
 * 
 * 
 * https://github.com/vitejs/awesome-vite#plugins
 */
import { defineConfig, loadEnv } from 'vite'

/**
 * postCssPxToRem 插件
 * npm i postcss-pxtorem -D
 * npm i postcss -D
 * npm i postcss-loader -D
 * npm i autoprefixer -D (待测试)
 * npm i postcss-import -D (待测试)
 * npm i postcss-url -D (待测试)
 * npm i postcss-aspect-ratio-mini -D (待测试)
 */
import postCssPxToRem from "postcss-pxtorem"
/**
 * vue 整合插件
 * npm i @vitejs/plugin-vue -D
 * npm i vue -D
 * npm i vue-router -D
 * npm i vuex -D
 * npm i axios -D
 */
import vue from '@vitejs/plugin-vue'
const url = require('url')
let parseURL = url.parse('http://user:[email protected]:8080/p/a/t/h?name=zhangsan&age=12#hash', true, true)

// 解析路径
const path = require('path')

/**
 * 设置server.open默认打开的浏览器
 * npm i open -D
 */
const open = require('open');
process.env.BROWSER = open.apps.chrome


/**
 * gzip 压缩配置
 * @type {boolean}
 * @default false
 * @description 是否开启 gzip 压缩
 * npm i vite-plugin-compression -D
 */
import viteCompression from 'vite-plugin-compression'


/**
 * mockjs 配置
 * npm (配置)
 * npm i mockjs -D
 * npm i vite-plugin-mock -D
 * npm i cross-env -D
 * npm i vite-plugin-mock-server -D
 * yarn (配置)
 * yarn add -D cross-env vite-plugin-mock
 * yarn add  mockjsD
 */
import { viteMockServe } from 'vite-plugin-mock';

/**
 * yarn add vite-plugin-mock-server
 */
// import mockServer from 'vite-plugin-mock-server'
// vite-plugin-mock-server
// options.plugins.push(mockServer({
//     logLevel: 'info',
//     urlPrefixes: ['/api/'],
//     mockRootDir: './mock',
//     mockJsSuffix: '.mock.js',
//     mockTsSuffix: '.mock.ts',
//     noHandlerResponse404: true,
//     mockModules: []
// }))

// export default ({ command, mode }) => {
//     console.log(command, mode);
export default defineConfig(({ command, mode }) => {
  let options = {

    // q:root配置项有什么用?
    // a:root配置项是为了解决打包后的资源路径问题,比如打包后的index.html中的资源路径是相对于index.html的,而不是相对于域名的,这样会导致资源加载失败,所以需要设置root,将资源路径设置为相对于域名的
    root: process.cwd(), //项目根目录(index.html 文件所在的位置
    base: '/', //开发或生产环境服务的公共基础路径
    // mode:'development' 'production'
    define: { // 这是node环境读不了process,直接在代码中使用   例如:web中直接能调用,process.env.NODE_ENV
      "process.env.NODE_ENV": process.env.NODE_ENV !== 'production' ? 'development' : 'production',
      __PBR_APP_VERSION__: '1.0'
    },
    plugins: [vue(),

      // q:mock插件有什么用?
      // a:mock插件是为了解决开发环境下的接口调试问题,可以在开发环境下模拟接口返回数据,而不用等待后端接口开发完成

      // q:viteCompression插件有什么用?
      // a:viteCompression插件是为了解决生产环境下的资源压缩问题,可以在生产环境下对资源进行压缩,减少资源体积,提高加载速度
      // import { viteMockServe } from 'vite-plugin-mock';
      // viteCompression方法的参数是一个对象,对象中的属性是vite-plugin-compression插件的配置项

      viteCompression({
        filter: /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i, // 需要压缩的文件
        threshold: 1024, // 文件容量大于这个值进行压缩
        algorithm: 'gzip', // 压缩方式
        ext: 'gz', // 后缀名
        deleteOriginFile: true, // 压缩后是否删除压缩源文件
      })
    ], // 需要用到的插件数组
    publicDir: 'public', // 静态资源文件夹,默认访问路径‘/’, 构建是会放在outDir根目录
    cacheDir: 'node_modules/.vite', // vite缓存文件目录,--force可以强制重新缓存
    resolve: {
      alias: { // 别名
        '@': path.resolve(__dirname, './src'),
        'comps': path.resolve(__dirname, './src/components'),
        'utils': path.resolve(__dirname, './src/utils'),
        'views': path.resolve(__dirname, './src/views'),
        'apis': path.resolve(__dirname, './src/apis')
      },
      dedupe: [], // 强制将相同依赖解析为同一副本, ======待研究怎么用======
      //package.json 相关 开

      // q:conditions 有什么用?举个例子
      // a:conditions 用于指定导入的模块的条件,比如指定导入的模块的环境
      conditions: [
        'import', // 导入时
        'require', // require时
        'node', // node环境
        'default', // 默认
        'import.meta', // 导入元数据
        'url', // url
        'script', // 脚本
        'worker', // worker
        'worker-src', // worker源
        'typeof', // 类型
        'browser', // 浏览器
        'esm', // esm
        'production', // 生产环境
        'development', // 开发环境
        'test', // 测试环境
        'electron', // electron
        'electron-renderer', // electron渲染器
        'electron-main', // electron主进程
        'nw', // nw
        'nwjs', // nwjs
        'web', // web
        'webworker', // webworker
        'global', // 全局
        'pure', // 纯
      ], // 场景条件, 
      mainFields: ['module', 'jsnext:main', 'jsnext'], // 入口点字段列表
      //package.json 相关 关
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], //导入时想要省略的扩展名列表
    },

    // q:CSS配置项有什么用?
    // a:CSS配置项是用来配置css相关的配置项
    CSS: {
      postcss: {
        plugins: [
          //import postCssPxToRem from "postcss-pxtorem"
          //npm i postcss-pxtorem 适配移动端配置
          // q:postCssPxToRem 为什么不用px2rem-loader
          // a:px2rem-loader 会把所有的px都转换成rem,但是有些px不需要转换,比如border-width:1px;这种就不需要转换
          postCssPxToRem({ // px转rem
            rootValue({ file }) { // 根元素字体大小 rootValue
              return file.indexOf('vant') !== -1 ? 37.5 : 75 // vant组件库字体大小为37.5,其他为75
            }, // 根元素字体大
            propList: ['*'], // 需要转换的属性,这里选择全部都进行转换
            selectorBlackList: ['van-'] // 不需要转换的选择器

          })
        ]
      }
      // modules:'',

      // preprocessorOptions: {},
    },

    // q:JSON配置项有什么用
    // a:JSON配置项是用来配置导入json文件的

    JSON: {
      namedExports: true, // 是否支持从 .json 文件中进行按名导入
      stringify: false, // 若设置为 true,性能好,单不支持按名导入
    },

    // q:esbuild配置项有什么用?
    // a:esbuild是一个JavaScript和TypeScript的构建工具,它可以在浏览器中运行,也可以在Node.js中运行,它可以将JavaScript和TypeScript代码转换为更快的JavaScript代码
    esbuild: { // esbuild配置项,false为关闭esbuild
      include: /\.[jt]sx?$/, // 匹配文件
      exclude: /node_modules/, // 排除文件
      // jsxInject: `import vue from 'vue'`, // 自动注入到每个jsx文件的顶部
      // jsxFactory: 'React.createElement', // 自定义jsx工厂函数
      // jsxFragment: 'React.Fragment', // 自定义jsx片段函数
      // tsconfigRaw: {}, // 自定义tsconfig.json
      // target: 'es2015', // 编译目标
    }, // esbuild配置项,false为关闭esbuild

    // q:assetsInclude配置项有什么用?
    // a:assetsInclude配置项是用来配置静态资源文件夹的,比如你的静态资源文件夹是static,那么你就可以配置assetsInclude: 'static',这样vite就会把static文件夹下的文件都当做静态资源文件处理
    assetsInclude: '', // 静态资源文件夹,默认访问路径‘/’, 构建是会放在outDir根目录
    logLevel: 'info', // 控制台输出级别,默认info,'info' | 'warn' | 'error' | 'silent'
    clearScreen: true, // 清屏, --clearScreen false
    envDir: './', //默认 root
    server: {
      host: '0.0.0.0',
      port: 9999, // 端口,若端口被占用时,自动尝试下一个端口
      
      // q:strictPort配置项有什么用?
      // a:strictPort配置项是用来配置端口被占用时直接退出的,比如你的端口是9999,但是9999被占用了,那么你就可以配置strictPort: true,这样vite就会直接退出
      strictPort: true, // 若端口被占用时直接退出
      cssPreprocessOptions: {
        less: {
          javascriptEnabled: true,
        },
      },

      // q:https配置项有什么用?
      // a:https配置项是用来配置https的,比如你的后端接口是https://localhost:3000,那么你就可以配置https: true,这样vite就会把https://localhost:3000作为后端接口
      // https: {
      // host: 'localhost',
      // port: 443,
      // key: fs.readFileSync('path/to/key'),
      // cert: fs.readFileSync('path/to/cert'),
      // },
      https: false, // 启用 TLS + HTTP/2 配置,注意:当 server.proxy 选项 也被使用时,将会仅使用 TLS。false则关闭

      // open: {
      //   app: {
      //     name: 'chrome',
      //     args: ['--incognito'],
      //   },
      //   path: '/foo',
      //   options: {
      //     wait: true,
      //   },
      // },
      open: '/', // 项目启动时自动打开浏览器,可以设置默认打开的路径

      // q:proxy配置项有什么用?
      // a:proxy配置项是用来配置代理的,比如你的后端接口是http://localhost:3000,那么你就可以配置proxy: { '/api': 'http://localhost:3000' },这样vite就会把/api开头的请求都代理到http://localhost:3000
      proxy: { // 服务器代理 https://github.com/http-party/node-http-proxy#options
        '/foo': 'http://localhost:4567/foo',
        '/apidd': {
          target: loadEnv(mode, process.cwd()).VITE_APP_SERVER_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, ''),
          configure: (proxy, options) => {
            // proxy 是 'http-proxy' 的实例
          },
        },
        '^/fallback/.*': { // 正则
          target: loadEnv(mode, process.cwd()).VITE_APP_SERVER_FALLBACK_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/fallback/, '')
        },
      },
      cors: true, // 跨域,默认允许任何源 或 {origin: 'http://example.com',optionsSuccessStatus: 200}

      //q:force配置项有什么用?
      //a:force配置项是用来配置强制依赖预构建的,比如你的项目依赖了vue,那么你就可以配置force: true,这样vite就会把vue预构建
      force: false, // 强制依赖预构建

      // q:fsServe配置项有什么用?
      // a:fsServe配置项是用来配置是否启用文件系统访问的,比如你的项目依赖了vue,那么你就可以配置fsServe: true,这样vite就会把vue预构建
      fsServe: { // 配置文件系统访问
        root: process.cwd(),
        strict: true,
      },

      // q:hmr配置项有什么用?
      // a:hmr配置项是用来配置是否启用热模块替换的,比如你的项目依赖了vue,那么你就可以配置hmr: true,这样vite就会把vue预构建 https://www.cnblogs.com/zhongweiv/p/14488838.html
      hmr: true, //禁用或配置 HMR 连接
      /**
       * { 
       *    protocol?: string, 
       *    host?: string, 
       *    port?: number, 
       *    path?: string, 
       *    timeout?: number, 
       *    overlay?: boolean, // 屏蔽开发服务器错误提示
       *    clientPort?: number, 
       *    server?: Server 
       * }
       */
      watch: {
        usePolling: false, // 是否使用轮询
        interval: 100, // 多久检查一次变动
        binaryInterval: 300, // 监听二进制文件时的轮询间隔
        disableGlobbing: false, // 是否禁用 globbing,如果你的文件夹中有大量文件,可以尝试禁用它
      }, //传递给 chokidar 的文件系统监听器选项 , 
      middlewareMode: 'html', // 
      // https://cn.vitejs.dev/guide/ssr.html#setting-up-the-dev-server  ======待研究怎么用======
      /**
       * 以中间件模式创建 Vite 服务器。(不含 HTTP 服务器)
       * 'ssr' 将禁用 Vite 自身的 HTML 服务逻辑,因此你应该手动为 index.html 提供服务。
       * 'html' 将启用 Vite 自身的 HTML 服务逻辑。
       */
    },

    // q:build配置项有什么用?
    // a:build配置项是用来配置构建的
    build: { // 构建
      target: 'modules', // 构建目标格式,默认是modules,也可以是esbuild配置项,https://esbuild.github.io/api/#target
      outDir: 'dist', // 构建输出路径
      assetsDir: 'assets', //静态资源文件夹,和outDir同级
      assetsInlineLimit: 4096, // 小于此大小的资源将被内联为 base64 编码,以减少请求数 4096 kb
      cssCodeSplit: true, // 运行css文件按chunk拆分,chunk加载时插入,如果false则所有的样式导出为一个css文件
      cssPreprocessOptions: { // css预处理器配置项
        scss: { // scss预处理器配置项
          additionalData: `$injectedColor: orange;` // 注入到每个scss文件的顶部
        }, // scss预处理器配置项
        less: { // less预处理器配置项
          javascriptEnabled: true // 允许在less文件中使用js
        },
        stylus: { // stylus预处理器配置项
          additionalData: `$injectedColor = orange` // 注入到每个stylus文件的顶部
        },
      }, // css预处理器配置项
      // cssModulesOptions: {}, // css模块配置项

      // q:sourcemap有什么用?
      // a:sourcemap是用来调试的,当你的代码出错时,你可以通过sourcemap找到出错的代码位置
      sourcemap: false, // 构建后是否生成sourcemap文件 
      /*
       * true,将会创建一个独立的 source map 文件
       * 'inline',source map 将作为一个 data URI 附加在输出文件中
       * 'hidden' 的工作原理与 'true' 相似,只是 bundle 文件中相应的注释将不被保留。
       */
      rollupOptions: { // rollup配置项  https://rollupjs.org/guide/en/#big-list-of-options
        external: ['vue', 'vue-router', 'vuex', 'axios', 'vant'], // 不打包的模块 https://rollupjs.org/guide/en/#external
        output: { // 输出配置 https://rollupjs.org/guide/en/#outputoptions
          manualChunks: { // 手动拆分代码块 https://rollupjs.org/guide/en/#outputmanualchunks
            vue: ['vue', 'vue-router', 'vuex'], // 拆分vue相关的包
            vant: ['vant'], // 拆分vant相关的包
            axios: ['axios'], // 拆分axios相关的包
          },
        },
      },
      // q:commonjsOptions这个配置有什么用?
      // a:commonjsOptions是@rollup/plugin-commonjs插件的配置,用于将CommonJS模块转换为ES模块,以便可以在Rollup中使用它们
      // q:为什么要转换CommonJS模块?
      // a:因为rollup只能打包ES模块,如果要打包CommonJS模块,就需要使用@rollup/plugin-commonjs插件
      commonjsOptions: { // @rollup/plugin-commonjs 插件的选项
        include: /node_modules/, // 需要转换的模块
        exclude: /node_modules\/(?!vite)/, // 不需要转换的模块
        sourceMap: false, // 是否生成sourcemap
        extensions: ['.js', '.cjs'], // 需要转换的文件后缀
        ignoreGlobal: false, // 忽略全局模块
        ignore: [], // 忽略的模块
        namedExports: {}, // 模块的命名导出
        transformMixedEsModules: false, // 是否转换混合的ES模块
        esmExternals: false, // 是否将外部模块视为ES模块
        requireReturnsDefault: 'auto', // 是否将require()视为返回default属性的函数
      }, // @rollup/plugin-commonjs 插件的选项
      dynamicImportVarsOptions: {}, // @rollup/plugin-dynamic-import-vars 的选项

      // q:lib这个配置有什么用?
      // a:lib是用来配置构建为库的
      // q:为什么要构建为库?
      // a:因为有时候我们需要将一些公共的方法或者组件抽离出来,作为一个独立的库,供其他项目使用
      // q:构建为库的配置项有哪些?
      // a:https://cn.vitejs.dev/guide/build.html#library-mode
      lib: {
        entry: path.resolve(__dirname, 'src/index.ts'), // 入口文件
        name: 'ViteLib', // 暴露的全局变量
        formats: ['es', 'umd'], // 构建的格式
        fileName: (format) => `vite-lib.${format}.js`, // 输出的文件名
      }, // 构建为库,https://cn.vitejs.dev/guide/build.html#library-mode
      /**
       * entry 是必须的因为库不能使用 HTML 作为入口。
       * name 则是暴露的全局变量,在 formats 包含 'umd' 或 'iife' 时是必须的。
       * 默认 formats 是 ['es', 'umd'] 。
       * fileName 是输出的包文件名,默认 fileName 是 package.json 的 name 选项,同时,它还可以被定义为参数为 format 的函数。
       */
      entry: "./main.ts", // 入口文件

      // q:manifest这个配置有什么用?
      // a:manifest是一个json文件,记录了构建后的文件名和文件内容的hash值,用于缓存控制
      // q:manifest文件是怎么生成的?
      // a:manifest文件是在构建时生成的,构建时会根据构建后的文件名和文件内容的hash值生成一个manifest.json文件
      // q:manifest文件有什么用?
      // a:manifest文件有两个作用,第一是用于缓存控制,第二是用于服务端渲染
      // q:manifest文件用于缓存控制是怎么做的?
      // a:manifest文件用于缓存控制是通过在html中引入manifest.json文件,然后在html中引入的js文件中通过读取manifest.json文件中的hash值来判断是否需要更新缓存
      // q:manifest文件用于服务端渲染是怎么做的?
      // a:manifest文件用于服务端渲染是通过在服务端渲染的时候,通过读取manifest.json文件中的hash值来判断是否需要更新缓存
      manifest: false,
      // q:minify这个配置有什么用?
      // a:minify用于压缩构建后的代码
      // q:minify这个配置是怎么做的?
      // a:minify是在构建时通过rollup-plugin-terser插件来实现的
      // q:rollup-plugin-terser这个插件是怎么做的?
      // a:rollup-plugin-terser这个插件是通过terser这个库来实现的
      // q:terser这个库是怎么做的?
      // a:terser这个库是通过esbuild来实现的
      // q:esbuild是怎么做的?
      // a:esbuild是通过esbuild-wasm来实现的
      minify: 'terser', // 构建后是否压缩代码,terser是默认的压缩器,也可以是esbuild配置项,https://esbuild.github.io/api/#minify
      TerserOptions: { // esbuild的压缩配置项 https://esbuild.github.io/api/#minify
        compress: { // 压缩配置项 https://esbuild.github.io/api/#minify
          drop_console: true, // 去掉console
          drop_debugger: true, // 去掉debugger
          pure_funcs: ['console.log'], // 去掉console.log
        },
      }, // terser混淆配置项
      cleanCssOptions: {}, // clean css 配置项, ======待研究怎么用======
      write: true, // 是否允许构建写入磁盘,false一般用在对构建做进一步处理
      emptyOutDir: true, // 构建前清库outDir目录
      brotliSize: true, //启用/禁用 brotli 压缩大小报告, 大型项目禁用可能提高构建速度
      chunkSizeWarningLimit: 500, //chunk 大小警告的限制(以 kbs 为单位
      // q:watch这个配置有什么用?
      // a:watch是用来监听文件变化的
      // q:watch这个配置是怎么做的?
      // a:watch是通过rollup的watch选项来实现的
      // q:rollup的watch选项是怎么做的?
      // a:rollup的watch选项是通过chokidar来实现的
      // q:chokidar是怎么做的?
      // a:chokidar是通过fs.watch来实现的
      // q:fs.watch是怎么做的?
      // a:fs.watch是通过fs.watchFile来实现的
      // q:fs.watchFile是怎么做的?
      // a:fs.watchFile是通过fs.stat来实现的
      // q:fs.stat是怎么做的?
      // a:fs.stat是通过fs.fstat来实现的
      // q:fs.fstat是怎么做的?
      // a:fs.fstat是通过fs.open来实现的
      // q:fs.open是怎么做的?
      // ...
      watch: {
        clearScreen: true, // 清除屏幕
        chokidar: {}, // chokidar的配置项
        exclude: [], // 不需要监听的文件
        include: [], // 需要监听的文件
        usePolling: false, // 是否监听文件变化
        interval: 100, // 多久检查一次文件变化
        binaryInterval: 300, // 多久检查一次二进制文件变化  https://rollupjs.org/guide/en/#watchoptions
        // chokidar: { // chokidar的配置项
        //   usePolling: true, // 是否监听文件变化
        //   interval: 100, // 多久检查一次文件变化
        //   binaryInterval: 300, // 多久检查一次二进制文件变化
        //   ignoreInitial: true, // 忽略初始添加的文件
        //   ignored: /node_modules/, // 忽略监听的文件
        //   awaitWriteFinish: { // 等待文件写入完成后再重新构建
        //     stabilityThreshold: 2000, // 等待多久
        //     pollInterval: 100, // 多久检查一次文件变化
        //   },
        // },

      }, // watchoptions,https://rollupjs.org/guide/en/#watch-options, 设置为 {} 则会启用 rollup 的监听器,代码改变时自动打包
    },
    // q:optimizeDeps这个配置有什么用?
    // a:optimizeDeps用于优化依赖 https://vitejs.dev/config/#dep-optimization-options
    // q:optimizeDeps这个配置是怎么做的?
    // a:optimizeDeps是通过rollup-plugin-node-resolve插件来实现的
    // q:rollup-plugin-node-resolve这个插件是怎么做的?
    // a:rollup-plugin-node-resolve这个插件是通过resolve这个库来实现的
    optimizeDeps: { // 依赖优化
      // entries, '' | [], // 预构建入口
      // exclude: [], // 预构建排查的依赖
      // include: [], // 不在 node_modules 中的依赖包预构建
      // keepNames:false, //打包器有时需要重命名符号以避免冲突
    },

    // q:ssr配置项有什么用?
    // a:ssr配置项用于服务端渲染
    ssr: { // 试验型,没做研究
      // external: [], //强制外部化的依赖
      // noExternal: '', // 防止外部化的依赖
      // target:'node', // SSR 服务器的构建目标
    }
  }
  if (command === 'serve') {
    // dev & serve

    //vite-plugin-mock
    //mock配置
    let prodMock = true;
    const viteMockServeOptions = {
      mockPath: 'mock',
      supportTs: false,
      ignore: undefined,
      watchFiles: true,
      localEnabled: command === 'serve',
      prodEnabled: command !== 'serve' && prodMock,
      injectCode: ``, // prodEnabled=true生效 main.{ts,js}
      injectFile: '', // default: path.resolve(process.cwd(),'src/main.{ts,js}')
      configPath: '', //default: vite.mock.config.ts
      logger: true, //请求是输入日志
    }
    options.plugins.push(viteMockServe(viteMockServeOptions))
    console.log('mock')
  } else {
    // build
    
    options.plugins.push(viteCompression(viteCompressionOptions))
  }
  return options
})

;