vue.config.js 基礎概述

vue.config.js 是 Vue CLI 項目中的可選配置文件,用於自定義項目的構建配置。該文件位於項目根目錄,採用 CommonJS 模塊語法導出一個配置對象。當該文件存在時,Vue CLI 會自動加載並應用其中的配置。

常用配置項詳解

publicPath

定義應用部署的基礎路徑。默認值為 '/',即假設應用部署在域名的根路徑下。如果應用部署在子路徑(如 /my-app/),需設置為 '/my-app/'。

示例:

module.exports = {
  publicPath: process.env.NODE_ENV === 'production' ? '/production-sub-path/' : '/'
}
outputDir

指定構建輸出目錄(默認 dist)。構建時目錄會被清除(除非配置了 noClean 為 true)。

示例:

module.exports = {
  outputDir: 'dist',
  assetsDir: 'static',
  filenameHashing: true
}
assetsDir

指定放置生成的靜態資源的目錄(相對於 outputDir)。默認 ''。

indexPath

指定生成的 index.html 的輸出路徑(相對於 outputDir)。默認 'index.html'。

filenameHashing

是否使用包含 hash 的文件名(用於緩存控制)。默認 true。

pages

配置多頁面應用。默認 undefined。

示例:

module.exports = {
  pages: {
    index: {
      entry: 'src/index/main.js',
      template: 'public/index.html',
      filename: 'index.html',
      chunks: ['chunk-vendors', 'chunk-common', 'index']
    },
    admin: {
      entry: 'src/admin/main.js',
      template: 'public/admin.html',
      filename: 'admin.html',
      chunks: ['chunk-vendors', 'chunk-common', 'admin']
    }
  }
}
lintOnSave

是否在開發環境下通過 eslint-loader 在每次保存時 lint 代碼。默認 true。

runtimeCompiler

是否使用包含運行時編譯器的 Vue 構建版本。默認 false。

transpileDependencies

默認情況下 babel-loader 會忽略 node_modules 中的文件。如需顯式轉譯依賴,可在此列出。

示例:

module.exports = {
  transpileDependencies: ['vuex-persist']
}
productionSourceMap

是否生成生產環境的 source map。默認 true。

crossorigin

配置生成的 HTML 中 <link rel="stylesheet"><script> 的 crossorigin 屬性。默認 undefined。

integrity

在生成的 HTML 中啓用 Subresource Integrity (SRI)。默認 false。

鏈式配置 (chainWebpack)

提供更細粒度的 webpack 配置修改能力,使用 webpack-chain 語法。

示例:

module.exports = {
  chainWebpack: config => {
    config.module
      .rule('vue')
      .use('vue-loader')
      .tap(options => {
        options.compilerOptions = {
          isCustomElement: tag => tag.startsWith('my-')
        }
        return options
      })
  }
}

配置 webpack (configureWebpack)

簡單合併到最終 webpack 配置的對象或函數。

對象形式示例:

module.exports = {
  configureWebpack: {
    plugins: [
      new MyAwesomeWebpackPlugin()
    ]
  }
}

函數形式示例:

module.exports = {
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      // 生產環境配置
    } else {
      // 開發環境配置
    }
  }
}

CSS 相關配置

css.requireModuleExtension

默認情況下,只有 *.module.[ext] 文件會被視為 CSS Modules 模塊。設置為 false 後可以去掉文件名中的 .module 並將所有 *.(css|scss|sass|less|styl(us)?) 文件視為 CSS Modules 模塊。默認 true。

css.extract

是否將組件中的 CSS 提取至一個獨立的 CSS 文件中(而不是動態注入到 JavaScript 中的 inline 代碼)。生產環境下默認 true,開發環境下默認 false。

css.sourceMap

是否為 CSS 開啓 source map。默認 false。

css.loaderOptions

向 CSS 相關的 loader 傳遞選項。

示例:

module.exports = {
  css: {
    loaderOptions: {
      css: {
        modules: {
          localIdentName: '[name]_[local]_[hash:base64:5]'
        }
      },
      sass: {
        prependData: `@import "@/styles/variables.scss";`
      }
    }
  }
}

devServer 開發服務器配置

devServer.port

指定開發服務器端口。默認 8080。

devServer.proxy

配置代理規則,解決跨域問題。

示例:

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
}
devServer.hot

啓用 webpack 的模塊熱替換特性。默認 true。

devServer.open

服務器啓動後自動打開瀏覽器。默認 false。

devServer.overlay

當出現編譯錯誤或警告時,在瀏覽器全屏顯示。默認 false。

其他高級配置

parallel

是否為 Babel 或 TypeScript 使用 thread-loader。默認 require('os').cpus().length > 1。

pwa

PWA 插件配置。

示例:

module.exports = {
  pwa: {
    name: 'My App',
    themeColor: '#4DBA87',
    msTileColor: '#000000',
    appleMobileWebAppCapable: 'yes',
    appleMobileWebAppStatusBarStyle: 'black',
    workboxPluginMode: 'GenerateSW'
  }
}
pluginOptions

傳遞參數給插件。

示例:

module.exports = {
  pluginOptions: {
    electronBuilder: {
      nodeIntegration: true,
      builderOptions: {
        win: {
          icon: 'build/icons/icon.ico'
        }
      }
    }
  }
}

配置合併策略

當需要擴展或修改內部 webpack 配置時,可通過 chainWebpack 或 configureWebpack 實現。chainWebpack 提供更細粒度的控制,而 configureWebpack 更簡單直觀。

性能優化配置

configureWebpack 優化示例
module.exports = {
  configureWebpack: {
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name(module) {
              const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]
              return `npm.${packageName.replace('@', '')}`
            }
          }
        }
      }
    }
  }
}
使用 DllPlugin 提升構建速度

雖然 Vue CLI 3+ 不再內置 DllPlugin,但可通過配置實現:

  1. 創建 webpack.dll.config.js
  2. 在 vue.config.js 中引用生成的 manifest 文件

多環境配置

可通過環境變量實現多環境配置:

module.exports = {
  publicPath: process.env.VUE_APP_BASE_URL,
  devServer: {
    proxy: process.env.VUE_APP_API_PROXY
  }
}

然後在項目根目錄創建:

  • .env.development
  • .env.production
  • .env.staging

自定義 loader 和 plugin

通過 chainWebpack 添加自定義 loader:

module.exports = {
  chainWebpack: config => {
    config.module
      .rule('yaml')
      .test(/\.ya?ml$/)
      .use('yaml-loader')
      .loader('yaml-loader')
      .end()
  }
}

添加自定義 plugin:

const MyPlugin = require('./my-plugin')
module.exports = {
  configureWebpack: {
    plugins: [
      new MyPlugin()
    ]
  }
}

完整配置示例

const path = require('path')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
  publicPath: process.env.NODE_ENV === 'production' ? '/production-path/' : '/',
  outputDir: 'dist',
  assetsDir: 'static',
  indexPath: 'index.html',
  filenameHashing: true,
  lintOnSave: process.env.NODE_ENV !== 'production',
  runtimeCompiler: false,
  transpileDependencies: [],
  productionSourceMap: false,
  crossorigin: undefined,
  integrity: false,
  css: {
    extract: true,
    sourceMap: false,
    loaderOptions: {
      sass: {
        prependData: `@import "@/styles/variables.scss";`
      }
    }
  },
  devServer: {
    port: 8080,
    open: true,
    overlay: {
      warnings: true,
      errors: true
    },
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
    }
  },
  chainWebpack: config => {
    config.module
      .rule('svg')
      .exclude.add(path.resolve(__dirname, 'src/icons'))
      .end()
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(path.resolve(__dirname, 'src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()
  },
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      config.plugins.push(
        new BundleAnalyzerPlugin({
          analyzerMode: 'static',
          reportFilename: 'bundle-report.html',
          openAnalyzer: false
        })
      )
    }
  },
  pluginOptions: {
    i18n: {
      locale: 'en',
      fallbackLocale: 'en',
      localeDir: 'locales',
      enableInSFC: true
    }
  },
  pwa: {
    name: 'My App',
    themeColor: '#4DBA87',
    workboxPluginMode: 'GenerateSW',
    workboxOptions: {
      skipWaiting: true
    }
  }
}

注意事項

  1. 修改 vue.config.js 後需要重啓開發服務器
  2. 某些配置可能在特定環境下不生效
  3. 優先使用 Vue CLI 提供的配置項,必要時再使用底層 webpack 配置
  4. 生產環境和開發環境配置可能有不同行為
  5. 可通過 vue inspect 命令查看最終 webpack 配置

調試配置

使用 Vue CLI 提供的 inspect 命令可以檢查最終生成的 webpack 配置:

vue inspect > output.js

或者查看特定規則:

vue inspect module.rules

常見問題解決方案

解決跨域問題

通過 devServer.proxy 配置代理:

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://backend-server:3000',
        changeOrigin: true,
        secure: false
      }
    }
  }
}
配置路徑別名
const path = require('path')
module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        '@': path.resolve(__dirname, 'src'),
        'components': path.resolve(__dirname, 'src/components')
      }
    }
  }
}
打包優化
  1. 使用 CDN 加載外部資源
  2. 配置 SplitChunks 分割代碼
  3. 啓用 gzip 壓縮
  4. 使用 DllPlugin 預編譯依賴
支持舊版瀏覽器

通過 browserslist 配置和 transpileDependencies 選項:

module.exports = {
  transpileDependencies: [
    'vuex-persist',
    'element-ui'
  ]
}

並在 package.json 中配置:

"browserslist": {
  "production": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  "development": [
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
  ]
}