前端工程化:webpack各项常用配置

前言

在项目开发中我们难免碰到需要对webpack配置更改的情况,今天就主要来讲一下在vue.config.js中对一些配置的更改,简单介绍一下loader的使用;用configureWebpack简单的配置;用chainWebpack做高级配置;包括对loader的添加,修改;以及插件的配置

1、首先简单介绍一下webpack中loader的简单使用:

loader:是webpack用来预处理模块的,在一个模块被引入之前,会预先使用loader处理模块的内容,在你打包的时候对某些内容需要loader来处理一下,比如css模块;默认webpack只会处理js代码,所以当我们想要去打包其他内容时,就需要相应的loader去处理某些内容
使用方法:
在配置文件中webpack.config.js加入module属性,该属性是一个对象,在这个属性中有一个rules字段,先上代码

module:{
        rules:[{
            test:/\.js$/,
            use:[{
                loader:'babel-loader',
                options: {
                presets: [
                  "es2015", "react"
                ],
                plugins: ["syntax-dynamic-import"]
          }
            }]
        }]
    }

rules是一个数组,你所有的loader配置都可以写在这个数组里,每个loader配置是一个对象,匹配不同的规则;
test:test后是一个正则表达式,匹配不同的文件类型;
use:在这个规则中,当你匹配了这个文件后,需要使用相应的loader去处理这类型的文件,use接收的是一个数组,意味着当他匹配到文件后,它可以启用很多的loader去处理文件的内容;
如果使用的是loader的默认配置,可以写use:['css-loader','style-loader'];
如果是需要用到额外配置则需要写成对象,讲配置写在options里;

当然,还会有其他的一些属性比如(exclude、include等),这里就不再详细赘述
在你使用这些loader之前需要用npm去安装这些包;

2、用configureWebpack简单的配置;

/ vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      new MyAwesomeWebpackPlugin()
    ]
  }
}

该对象将会被 webpack-merge 合并入最终的 webpack 配置。
如果你需要基于环境有条件地配置行为,或者想要直接修改配置,那就换成一个函数 (该函数会在环境变量被设置之后懒执行)。该方法的第一个参数会收到已经解析好的配置。在函数内,你可以直接修改配置,或者返回一个将会被合并的对象:

// vue.config.js
module.exports = {
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置...
    } else {
      // 为开发环境修改配置...
    }
  }
}

3、用chainWebpack做高级配置

Vue CLI 内部的 webpack 配置是通过 webpack-chain 维护的。这个库提供了一个 webpack 原始配置的上层抽象,使其可以定义具名的 loader 规则和具名插件,并有机会在后期进入这些规则并对它们的选项进行修改。

它允许我们更细粒度的控制其内部配置。接下来有一些常见的在 vue.config.js 中的 chainWebpack 修改的例子。
官方文档给我提供了一些简单的示例:
修改 Loader 选项

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('vue')
      .use('vue-loader')
        .loader('vue-loader')
        .tap(options => {
          // 修改它的选项...
          return options
        })
  }
}

添加一个新的 Loader

// vue.config.js
module.exports = {
  chainWebpack: config => {
    // GraphQL Loader
    config.module
      .rule('graphql')
      .test(/\.graphql$/)
      .use('graphql-tag/loader')
        .loader('graphql-tag/loader')
        .end()
  }
}

替换一个规则里的 Loader,

// 添加svg-sprite-loader
    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .tap(options => {
        options = {
          symbolId: 'icon-[name]'
        }
        return options
      })

修改插件的代码可以看下面的例子;
先上代码,今天主要讲我们项目中配置,配置的api地址:https://cli.vuejs.org/zh/conf...

const path = require('path')
const webpack = require('webpack')
module.exports = {
  // 修改output.path
  outputDir: 'dist',
  // 修改output.publishPath
  publishPath: './',
  chainWebpack: config => {
    // 添加全局scss文件
    const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
    types.forEach(type => { //匹配到所有需要导入的文件
      config.module.rule('scss').oneOf(type).use('style-resource')
        .loader('style-resources-loader')
        .options({
          patterns: [
            path.resolve(__dirname, 'src/css/base.scss')
          ]
        })
    })
    // 添加svg-sprite-loader
    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .tap(options => {
        options = {
          symbolId: 'icon-[name]'
        }
        return options
      })
    // 移除 prefetch 插件 //预加载
    config.plugins.delete('prefetch')
    // 引入
    const chunkFolder = process.env.NODE_ENV !== 'production' ? 'debug' : 'dist'
    config.plugin('dll-reference-plugin')
      .use(webpack.DllReferencePlugin)
      .tap(options => {
        options[0] = {
          context: __dirname,
          manifest: require(path.join(__dirname, `./src/common_chunk/${chunkFolder}/manifest.json`))
        }
        return options
      })
    config.plugin('add-asset-html-webpack-plugin')
      .use('add-asset-html-webpack-plugin')
      .tap(options => {
        options[0] = {
          filepath: path.resolve(__dirname, `./src/common_chunk/${chunkFolder}/lib_*.js`)
        }
        return options
      })
  }
}

上述代码里使用了style-resources-loader,可以自动化导入文件;
添加svg-sprite-loader的目的是为了将svg图片转换为svg标签插入html,以方便便我们使用类似以下方式,webpack里默认处理svg的loader是file-loader,所以要移除这个配置:

 

DllReferencePlugin这个插件是为了使第三方以来和我们自己编写的代码分开打包,提升打包速度;需要和add-asset-html-webpack-plugin这个插件一起使用;
使用这个插件打包后,在src/common_chunk这个文件夹下生成工具库,将第三方依赖打包到一个文件里,并生成一个所有库代码的一个索引manifest.json文件

 

 

ps:全局引入公共样式文件的另一种方法,这样也可以直接在使用公共样式了;

module.exports = {
  // ...
  css: {
    loaderOptions: {
      sass: {
        // 根据自己样式文件的位置调整
        data: `@import "@src/css/base.scss";`
      }
    }
  }
};

本文参考的文档:https://cli.vuejs.org/zh/guid...

 


webpack-chain是什么?经过链式的方式修改webpack的配置

//vue.config.js
module.exports={
  chainWebpack:(webpackConfig)=>{

  }
}

一、修改entry和output

 

chainWebpack: config => {
  config.entryPoints.clear() // 会把默认的入口清空
  config.entry('main').add('./src/main.js')//新增入口
  config.entry('routes').add('./src/app-routes.js')//新增入口


   config.output
        .path("dist")
        .filename("[name].[chunkhash].js")
        .chunkFilename("chunks/[name].[chunkhash].js")
        .libraryTarget("umd")
        .library();
}

// 其他的output配置
config.output
  .auxiliaryComment(auxiliaryComment)
  .chunkFilename(chunkFilename)
  .chunkLoadTimeout(chunkLoadTimeout)
  .crossOriginLoading(crossOriginLoading)
  .devtoolFallbackModuleFilenameTemplate(devtoolFallbackModuleFilenameTemplate)
  .devtoolLineToLine(devtoolLineToLine)
  .devtoolModuleFilenameTemplate(devtoolModuleFilenameTemplate)
  .filename(filename)
  .hashFunction(hashFunction)
  .hashDigest(hashDigest)
  .hashDigestLength(hashDigestLength)
  .hashSalt(hashSalt)
  .hotUpdateChunkFilename(hotUpdateChunkFilename)
  .hotUpdateFunction(hotUpdateFunction)
  .hotUpdateMainFilename(hotUpdateMainFilename)
  .jsonpFunction(jsonpFunction)
  .library(library)
  .libraryExport(libraryExport)
  .libraryTarget(libraryTarget)
  .path(path)
  .pathinfo(pathinfo)
  .publicPath(publicPath)
  .sourceMapFilename(sourceMapFilename)
  .sourcePrefix(sourcePrefix)
  .strictModuleExceptionHandling(strictModuleExceptionHandling)
  .umdNamedDefine(umdNamedDefine)

二、设置别名alias

const path = require('path');
function resolve (dir) {
    return path.join(__dirname, dir)
}
module.exports = {
    lintOnSave: true,
    chainWebpack: (config)=>{
        config.resolve.alias
            .set('@$', resolve('src'))
            .set('assets',resolve('src/assets'))
            .set('components',resolve('src/components'))
            .set('layout',resolve('src/layout'))
            .set('base',resolve('src/base'))
            .set('static',resolve('src/static'))
            .delete('base') // 删掉指定的别名
            // .clear()  会把全部别名都删掉
    }
}

三、修改代理proxy

devServe的配置,请见这里前端

  chainWebpack: config => {
    config.devServer.port(8888)
      .open(true)
      .proxy({'/dev': {
                 target: 'http://123.57.153.106:8080/',
                 changeOrigin: true,
                 pathRewrite: {
                   '^/dev': ''
                 }
               }
           })
  }
// chain其余队proxy的配置
config.devServer
  .bonjour(bonjour)
  .clientLogLevel(clientLogLevel)
  .color(color)
  .compress(compress)
  .contentBase(contentBase)
  .disableHostCheck(disableHostCheck)
  .filename(filename)
  .headers(headers)
  .historyApiFallback(historyApiFallback)
  .host(host)
  .hot(hot)
  .hotOnly(hotOnly)
  .https(https)
  .inline(inline)
  .info(info)
  .lazy(lazy)
  .noInfo(noInfo)
  .open(open)
  .openPage(openPage)
  .overlay(overlay)
  .pfx(pfx)
  .pfxPassphrase(pfxPassphrase)
  .port(port)
  .progress(progress)
  .proxy(proxy)
  .public(public)
  .publicPath(publicPath)
  .quiet(quiet)
  .setup(setup)
  .socket(socket)
  .staticOptions(staticOptions)
  .stats(stats)
  .stdin(stdin)
  .useLocalIp(useLocalIp)
  .watchContentBase(watchContentBase)
  .watchOptions(watchOptions)

四、添加插件及修改插件参数

插件相关配置请见这里

添加插件node

// 添加API
config
  .plugin(name)
  .use(WebpackPlugin, args)

// 一个例子
const fileManager = require("filemanager-webpack-plugin");
...
//注意:use部分,不能使用new的方式建立插件实例
webpackConfig.plugin("zip").use(fileManager, [
    {
      onEnd: {
        archive: [
          {
            source: "dist",
            destination: zipName
          }
        ]
      }
    }
  ]);

修改插件参数

// 可使用tap方式,修改插件参数
config
  .plugin(name)
  .tap(args => newArgs)

// 一个例子
config
  .plugin('env')
  //使用tag修改参数
  .tap(args => [...args, 'SECRET_KEY']);

五、修改插件初始化及移除插件

 

修改插件初始化

config
  .plugin(name)
  .init((Plugin, args) => new Plugin(...args));


移除插件

 chainWebpack: config => {
  config.plugins.delete('prefetch')
  // 移除 preload 插件
  config.plugins.delete('preload');
 }

六、在xx插件前调用/在xx插件以后调用


有时候须要xx插件在aa插件以前调用。

config
  .plugin(name)
    .before(otherName)

// 一个例子:ScriptExtWebpackPlugin插件在HtmlWebpackTemplate插件前调用

config
  .plugin('html-template')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin)
    .before('html-template');


有时候须要xx插件在aa插件以后调用。


config
  .plugin(name)
    .after(otherName)

// 一个例子html-template在script-ext以后调用

config
  .plugin('html-template')
    .after('script-ext')
    .use(HtmlWebpackTemplate)
    .end()
  .plugin('script-ext')
    .use(ScriptExtWebpackPlugin);

八、代码分割及性能优化 optimizations

config.optimization
  .concatenateModules(concatenateModules)
  .flagIncludedChunks(flagIncludedChunks)
  .mergeDuplicateChunks(mergeDuplicateChunks)
  .minimize(minimize) //boolean,默认为true,是否开启压缩
  .namedChunks(namedChunks)
  .namedModules(namedModules)
  .nodeEnv(nodeEnv)
  .noEmitOnErrors(noEmitOnErrors)
  .occurrenceOrder(occurrenceOrder)
  .portableRecords(portableRecords)
  .providedExports(providedExports)
  .removeAvailableModules(removeAvailableModules)
  .removeEmptyChunks(removeEmptyChunks)
  .runtimeChunk(runtimeChunk)
  .sideEffects(sideEffects)
  .splitChunks(splitChunks)//object:代码分割。默认状况下,webpack v4 +为动态导入的模块提供了开箱即用的新通用块策略。
  .usedExports(usedExports)

//举个例子

config.optimization.splitChunks({
     chunks: "async", // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
     minSize: 30000, // 最小尺寸,30000
     minChunks: 1, // 最小 chunk ,默认1
     maxAsyncRequests: 5, // 最大异步请求数, 默认5
     maxInitialRequests : 3, // 最大初始化请求书,默认3
     automaticNameDelimiter: '~',// 打包分隔符
     name: function(){}, // 打包后的名称,此选项可接收 function
     cacheGroups:{ // 这里开始设置缓存的 chunks
         priority: 0, // 缓存组优先级
         vendor: { // key 为entry中定义的 入口名称
             chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是async) 
             test: /react|lodash/, // 正则规则验证,若是符合就提取 chunk
             name: "vendor", // 要缓存的 分隔出来的 chunk 名称 
             minSize: 30000,
             minChunks: 1,
             enforce: true,
             maxAsyncRequests: 5, // 最大异步请求数, 默认1
             maxInitialRequests : 3, // 最大初始化请求书,默认1
             reuseExistingChunk: true // 可设置是否重用该chunk
         }
     }
});

九、自定义代码压缩工具

webpack4.x默认使用的TerserPlugin作代码压缩。

 


//使用
config.optimization.minimizer.use(WebpackPlugin,args);
//删除
config.optimization.minimizers.delete(name)



// 一个例子

config.optimization
  .minimizer('css')
  .use(OptimizeCSSAssetsPlugin, [{ cssProcessorOptions: { safe: true } }])

// Minimizer plugins can also be specified by their path, allowing the expensive require()s to be
// skipped in cases where the plugin or webpack configuration won't end up being used.
config.optimization
  .minimizer('css')
  .use(require.resolve('optimize-css-assets-webpack-plugin'), [{ cssProcessorOptions: { safe: true } }])

//是要tap修改插件参数
config.optimization
  .minimizer('css')
  .tap(args => [...args, { cssProcessorOptions: { safe: false } }])

十、添加一个新的 Loader

首先请先了解一下webpack如何配置loader. 官网连接


config.module
  .rule(name)
    .use(name)
      .loader(loader)
      .options(options)

// 一个例子

 config.module
      .rule('graphql')
      .test(/\.graphql$/)
      .use('graphql-tag/loader')
        .loader('graphql-tag/loader')
        .end()
// 若是是非webpack-chain的话
module:{
  rules:[
    {
      test:/\.graphql$/,
      use::[
        {
          loader:"graphql-tag/loader"
        }
      ]
    }
  ]
}

十一、 修改Loader

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('vue')
      .use('vue-loader')
        .loader('vue-loader')
        .tap(options => {
          // 修改它的选项...
          return options
        })
  }
}
注意 对于 CSS 相关 loader 来讲,咱们推荐使用 css.loaderOptions 而不是直接链式指定 loader。这是由于每种 CSS 文件类型都有多个规则,而 css.loaderOptions 能够确保你经过一个地方影响全部的规则。

十二、 替换一个规则里的 Loader

 

// vue.config.js
module.exports = {
  chainWebpack: config => {
    const svgRule = config.module.rule('svg')

    // 清除已有的全部 loader。
    // 若是你不这样作,接下来的 loader 会附加在该规则现有的 loader 以后。
    svgRule.uses.clear()

    // 添加要替换的 loader
    svgRule
      .use('vue-svg-loader')
        .loader('vue-svg-loader')
  }
}

十三、使用when作条件配置

 

consif.when(condition,truthyFunc,falsyFunc)

// 一个例子,当构建生产包时添加minify插件,不然设置构建类型为source-map
// devtool请见:https://www.webpackjs.com/configuration/devtool/
config
  .when(process.env.NODE_ENV === 'production',
    config => config.plugin('minify').use(BabiliWebpackPlugin),
    config => config.devtool('source-map')
  );

十四、使用toString()查看chain对应的webpack配置

注意 使用toString()生成的数据,不能直接在webpack上使用。

config
  .module
    .rule('compile')
      .test(/\.js$/)
      .use('babel')
        .loader('babel-loader');

config.toString();

/*
{
  module: {
    rules: [
      /* config.module.rule('compile') */
      {
        test: /\.js$/,
        use: [
          /* config.module.rule('compile').use('babel') */
          {
            loader: 'babel-loader'
          }
        ]
      }
    ]
  }
}
*/

 

参考

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值