Webpack

vue 常用 webpack 配置

const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
    // build时构建文件的目录 构建时传入 --no-clean 可关闭该行为
    outputDir: 'dist',

    // build时放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
    // assetsDir: '',

    // 指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。
    // indexPath: 'index.html',

    // 默认在生成的静态资源文件名中包含hash以控制缓存
    filenameHashing: true,

    // 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码 (在生产构建时禁用 eslint-loader)
    lintOnSave: process.env.NODE_ENV !== 'production',

    // 是否使用包含运行时编译器的 Vue 构建版本
    runtimeCompiler: true,

    // Babel 显式转译列表
    transpileDependencies: [],

    // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建
    productionSourceMap: false,

    // 设置生成的 HTML 中 <link rel="stylesheet"> 和 <script> 标签的 crossorigin 属性(注:仅影响构建时注入的标签)
    // crossorigin: '',

    // 在生成的 HTML 中的 <link rel="stylesheet"> 和 <script> 标签上启用 Subresource Integrity (SRI)
    // integrity: false,

    // 所有 webpack-dev-server 的选项都支持
    devServer: {
      open: true, // 是否自动打开浏览器
      // 设置主机地址
      host: '0.0.0.0',
      // 设置默认端口
      port: 8080,
      // 设置代理
      proxy: {
        '/api': {
          // 目标 API 地址
          target: 'http://192.168.10.33:8082/',
          // 是否要代理 websockets
          ws: false,
          // 将主机标头的原点更改为目标URL
          changeOrigin: true,
          pathRewrite: {
            '^/api': '/'
          }
        }
      }
    },

    // 如果这个值是一个对象,则会通过 webpack-merge 合并到最终的配置中
    // 如果你需要基于环境有条件地配置行为,或者想要直接修改配置,那就换成一个函数 (该函数会在环境变量被设置之后懒执行)。该方法的第一个参数会收到已经解析好的配置。在函数内,你可以直接修改配置,或者返回一个将会被合并的对象
    configureWebpack: {
      plugins: [
        new MyAwesomeWebpackPlugin()
      ]
    },
    configureWebpack: config => {
      if (process.env.NODE_ENV === 'production') {
        // 为生产环境修改配置...
      } else {
        // 为开发环境修改配置...
      }
    },
    
    
    // 对内部的 webpack 配置(比如修改、增加Loader选项)(链式操作)
    chainWebpack: config => {
      config.module
        .rule('vue')
        .use('vue-loader')
          .loader('vue-loader')
          .tap(options => {
            // 修改它的选项...
            return options
          })
    },
    chainWebpack: config => {   // 举例添加一个loader
      // GraphQL Loader
      config.module
        .rule('graphql')
        .test(/\.graphql$/)
        .use('graphql-tag/loader')
          .loader('graphql-tag/loader')
          .end()
     },
    chainWebpack: config => {
      const rule = config.module.rule('svg')
      rule.exclude.add(path.resolver('./src/assets/icons/svg')) // 排除某个路径

      const svgRule = config.module.rule('auto-svg')
      // 清除已有的 loader
      svgRule.uses.clear()
      // 添加要替换的 loader
      svgRule
        .test(/\.(svg)(\?.*)?$/)
        .include
        .add(path.join(__dirname, 'src/assets/icons'))
        .end()
        .use('vue-svg-loader')
        .loader('vue-svg-loader')
        .options({
          symbolId: 'icon-[name]'
        })

      // 生产环境启用gzip压缩
      if (process.env.NODE_ENV === 'production') {
        config
          .plugin('compression')
          .use(CompressionPlugin, {
            assets: '[path].gz[query]',
            algorithm: 'gzip',
            test: new RegExp('\\.(' + ['js','css'].join('|') + ')$'),
            threshold: 10240,
            minRatio: 0.8,
            cache: true
          })
        // 50k以下图片转为base64
        config.module
          .rule('images)
          .use('url-loader')
          .loader('url-loader')
          .tap(options => Object.assign(options, {limit: 1024 * 50}))
      }
    },
    
    // css的处理
    css: {
      // 当为true时,css文件名可省略 module 默认为 false
      // modules: true,
      // 是否将组件中的 CSS 提取至一个独立的 CSS 文件中,当作为一个库构建时,你也可以将其设置为 false 免得用户自己导入 CSS
      // 默认生产环境下是 true,开发环境下是 false
      // extract: false,
      // 是否为 CSS 开启 source map。设置为 true 之后可能会影响构建的性能
      sourceMap: false,
      //向 CSS 相关的 loader 传递选项(支持 css-loader postcss-loader sass-loader less-loader stylus-loader)
      loaderOptions: {
        css: {},
        less: {},
        sass: {
          data: `
            @import "@/styles/mixin.scss";
            @import "@/styles/_var.scss";
          `
        }
      }
    },

    // 是否为 Babel 或 TypeScript 使用 thread-loader
    // parallel: require('os').cpus().length > 1,

    // 向 PWA 插件传递选项
    // pwa: {},

    // 可以用来传递任何第三方插件选项
    // pluginOptions: {}
    
}

任何放置在 public 文件夹的静态资源都会被简单的复制,而不经过 webpack。你需要通过绝对路径来引用它们。什么情况下使用:

  • 你需要在构建输出中指定一个文件的名字。
  • 你有上千个图片,需要动态引用它们的路径。
  • 有些库可能和 webpack 不兼容,这时你可以将其用一个独立的 <script> 标签引入

[object Module] 解决方案

使用webpack4构建的项目,出现 src="[object Module]" 的原因及解决方案。 Vue官方文档中说了 vue-loader 的基本原理,他会将Vue模板中的 <img src="../image.png"> 转为下面这段JS代码:

createElement('img', {
  attrs: {
    src: require('../image.png')  // require()是CommonJS模块语法
  }
})

对于图像我们在Webpack中一般使用 url-loader 来处理

{
  "test": /\.(png|jpe?g|gif|svg)$/,
  "loader": "url-loader",
  "options": {
    "limit": 1024
  }
}

然而这样最后生成的图像会变成 <img src="[object Module]">,无法显示。 这是因为 file-loader 默认采用ES模块语法,即 import '../image.png';然而 Vue 生成的是 CommonJS 模块语法,即 require('../image.png');二者不一致。要么让 file-loader 或 url-loader 采用CommonJS语法,要么让Vue采用ES语法。

刚好 file-loader 或 url-loader 有一个 esModule 选项能调整,将其设置为 false 即可

{
  "test": /\.(png|jpe?g|gif|svg)$/,
  "loader": "url-loader",
  "options": {
    "limit": 1024,
    "esModule": false
  }
}