vue.config.js中的webpack配置,优化及多页面应用开发

目录

  • 一、vue.config.js中常用的配置
    • 1、导出模块
    • 2、publicPath 部署应用包的基本Url
    • 3、outputDir 输出文件目录
    • 4、assetsDir 打包后生成的静态资源目录
    • 5、lintOnSave
    • 6、productionSourceMap 生产环境的 source map
    • 7、devServer
    • 8、 chainWebpack webpack配置
    • 9、configureWebpack webpack配置
      • configureWebpack和chainWebpack区别
    • 10、css相关配置
    • 11、pages
    • 12、其他
  • 二、优化
    • 1、优化打包chunk-vendors.js
    • 2、打包时去除打印信息
    • 3、开启gizp压缩
    • 4、vue-cli3 图片压缩【image-webpack-loader】使用
    • 5、移动端.px2rem 响应样式
  • 三、多页面应用开发与配置
    • 搭建项目
        1. 创建项目
        1. 搭建文件结构
        1. 配置路由
        1. 配置vue.config.js
    • 注意事项
    • 设置页面动态标题
    • 路由子模块设置
  • 四、vue.config.js完整代码

官方文档

vue-cli3以下版本中,关于webpack的一些配置都在config目录文件中,可是vue-cli3以上版本中,没有了config目录,那该怎么配置webpack呢?
3.x初始化项目后没有了build和config文件,如果你想对webpack相关内容进行配置,需要自己在根目录下(与package.json同级)创建一个vue.config.js文件,这个文件一旦存在,那么它会被 @vue/cli-service 自动加载。(但需要我们自己手动创建哦vue.config.js,跟package.json同级)

一、vue.config.js中常用的配置

在配置中绝大多数都是(可选项)

1、导出模块

常规操作还是用到了commjs语法

module.exports = {

}

2、publicPath 部署应用包的基本Url

部署应用包的基本Url,默认/, 可以设置为相对路径./,这样打出来的包,可以部署到任意路径上

let developmentPath='./';//开发环境-npm run serve时引用文件路径
let productionPath='./';//生产环境-npm run build打包后引用文件路径
module.exports = {
    publicPath: process.env.NODE_ENV === 'production' ? productionPath: developmentPath, // 基本路径-引用文件的路
}

3、outputDir 输出文件目录

输出文件目录(打包后生成的目录,默认dist)

module.exports = {
  outputDir: __dirname + '/server/dist', //build之后静态文件输出路径
  //outputDir: 'dist',
}

4、assetsDir 打包后生成的静态资源目录

打包后生成的静态资源目录,默认“ ” ,也就是我们打包后的css,js等存放的位置

module.exports = {
 assetsDir: 'static',
}

5、lintOnSave

是否在保存的时候检查

module.exports = {
    lintOnSave: process.env.NODE_ENV !== 'production',// eslint-loader 
}

6、productionSourceMap 生产环境的 source map

生产环境的 source map,可以将其设置为 false 以加速生产环境构建,默认值是true

module.exports = {
    productionSourceMap: false,
}

7、devServer

可通过 devServer.proxy解决前后端跨域问题(反向代理)

module.exports = {
// 反向代理
  devServer: {
    index: '/login.html',   //默认打开文件
    open: true,             //自动打开浏览器
    host: 'localhost',      //默认打开域名
    port: 8080,             //默认打开端口号
    https: false,           //开启关闭https请求
    hotOnly: false,         //热更

    proxy: {
      // 配置跨域
      '/api': {
        target: 'http://dev.aabb.cn:8082/', //代理地址,这里设置的地址会代替axios中设置的baseURL
        ws: true,   //// proxy websockets
        changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
        pathRewrite: {                //pathRewrite方法重写url
          '^/api': '/',
        },
      },
    },
  },
} 

扩展: hot 和 hotOnly 的区别是在某些模块不支持热更新的情况下,前者会自动刷新页面,后者不会刷新页面,而是在控制台输出热更新失败

8、 chainWebpack webpack配置

module.exports = {
  chainWebpack: (config) => {
    config.plugins.delete('preload')
    config.plugins.delete('prefetch')

    config.module
      .rule('svg')
      .exclude.add(resolve('src/assets/icons'))
      .end()

    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/assets/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]',
      })
      .end()

    const imagesRule = config.module.rule('images')
    imagesRule.uses.clear() //清除原本的images loader配置
    imagesRule
      .test(/\.(jpg|gif|png|svg)$/)
      .exclude.add(path.join(__dirname, '../node_modules')) //不对node_modules里的图片转base64
      .end()
      .use('url-loader')
      .loader('url-loader')
      .options({ name: 'img/[name].[hash:8].[ext]', limit: 6000000 })

    config.optimization.splitChunks({
      cacheGroups: {

        vendors: {
          name: 'chunk-vendors',
          minChunks: pageNum,
          test: /node_modules/,
          priority: -10,
          chunks: 'initial',
        },

        elementUI: {
          name: 'chunk-elementUI', // split elementUI into a single package
          priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
          test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
        },

        commons: {
          name: 'chunk-commons',
          test: resolve('src/components'), // can customize your rules
          minChunks: 3, //  minimum common number
          priority: 5,
          reuseExistingChunk: true,
        },
      },
    })
  },
}

扩展:
Preload: 用于标记页面加载后即将用到的资源,浏览器将在主体渲染前加载preload标记文件。Vue CLI 应用会为所有初始化渲染需要的文件自动生成 preload 提示;

Prefetch: 用于标记浏览器在页面加载完成后,利用空闲时间预加载的内容。Vue CLI 应用默认为所有作为 async chunk 生成的 JavaScript 文件 (通过动态 import() 按需 code splitting 的产物) 自动生成prefetch提示。

9、configureWebpack webpack配置

webpack配置

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const CompressionWebpackPlugin = require('compression-webpack-plugin')

const productionGzipExtensions = ['js', 'css']
const Version = 'V6.1'
const Timestamp = new Date().getTime()

module.exports = {
    webpack配置
    configureWebpack: (config) => {
          // 为生产环境修改配置
        if (process.env.NODE_ENV === 'production') {
      
            config.plugins.push(
                new UglifyJsPlugin({
                    uglifyOptions: {
                        compress: {
                            drop_debugger: true,//生产环境自动删除debugger
                            drop_console: true, //生产环境自动删除console
                        },
                        warnings: false,
                    },
                    sourceMap: false,   //关掉sourcemap 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
                    parallel: true, //使用多进程并行运行来提高构建速度。默认并发运行数:os.cpus().length - 1。
                }),


                new CompressionWebpackPlugin({
                    filename: '[path].gz[query]',
                    algorithm: 'gzip',
                    test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
                    threshold: 10240,
                    minRatio: 0.8,
                })
            )
        }

        // 在这里配置后,减少了压缩的包内容,需要在public/index.html通过cdn方式再引入,注意对应的版本
        config.externals = { 
            vue: 'Vue',
            'vue-router': 'VueRouter',
            vuex: 'Vuex',
            axios: 'axios',
            jquery: '$',
            moment: 'moment',
            'mint-ui': 'MINT'
        },


         // 别名配置
        Object.assign(config, {
            // 开发生产共同配置
            resolve: {
                alias: {
                '@': path.resolve(__dirname, './src'),
                '@c': path.resolve(__dirname, './src/components'),
                '@p': path.resolve(__dirname, './src/pages')
                }
            }
        }),

        config.output.filename = `[name].${Version}.${Timestamp}.js`  //打包生成的文件
        config.output.chunkFilename = `[name].${Version}.${Timestamp}.js`
    },
 }

扩展:

  1. UglifyJS Webpack:
    Plugin插件用来缩小(压缩优化)js文件,至少需要Node v6.9.0和Webpack v4.0.0版本。
  2. compression-webpack-plugin
    Vue配置compression-webpack-plugin实现Gzip压缩
  3. chunkFilename
    和webpack.optimize.CommonsChunkPlugin插件的作用差不多,都是用来将公共模块提取出来,但是用法不一样
entry:{
    main:__dirname + '/app/main.js',
    index:__dirname + '/app/index.js'      
},
output:{
    path:__dirname + '/public', //通过HtmlWebpackPlugin插件生成的html文件存放在这个目录下面
    filename:'/js/[name].js', //编译生成的js文件存放到根目录下面的js目录下面,如果js目录不存在则自动创建
    /*
     * chunkFilename用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块则不会生成任何chunk块文件
     * 比如在main.js文件中,require.ensure([],function(require){alert(11);}),这样不会打包块文件
     * 只有这样才会打包生成块文件require.ensure([],function(require){alert(11);require('./greeter')})
     * 或者这样require.ensure(['./greeter'],function(require){alert(11);})
     * chunk的hash值只有在require.ensure中引入的模块发生变化,hash值才会改变
     * 注意:对于不是在ensure方法中引入的模块,此属性不会生效,只能用CommonsChunkPlugin插件来提取
     * */
    chunkFilename:'js/[chunkhash:8].chunk.js'
},

configureWebpack和chainWebpack区别

在这里configureWebpack和chainWebpack的作用相同,唯一的区别就是他们修改webpack配置的方式不同:

  1. chainWebpack通过链式编程的形式,来修改默认的webpack配置
  2. configureWebpack通过操作对象的形式,来修改默认的webpack配置
    如果对一个loader或plugin修改的配置如果是一项的话推荐 chainWebpack、如果是多项的话用configureWebpack直接覆写

10、css相关配置

这里配置了全局sass 需要安装的依赖 sass-loader less-loader

 css: {
        loaderOptions: {
            scss: {
                additionalData: `@import "@/assets/css/reset.scss";@import "@/assets/css/globle.scss";`  //注意配置的键名
            },
            postcss: {
                plugins: [
                    //remUnit这个配置项的数值是多少呢??? 通常我们是根据设计图来定这个值,原因很简单,便于开发。
                    //假如设计图给的宽度是750,我们通常就会把remUnit设置为75,这样我们写样式时,可以直接按照设计图标注的宽高来1:1还原开发。
                    require('postcss-px2rem')({
                        remUnit: 37.5
                    })
                ]
            }
        }
    },

由于 sass-loader 版本不同,loaderOptions 中的 additionalData 的键名也不同

  • sass-loader loader v8-, 这个选项名是 "data",
  • sass-loader loader v8中, 这个选项名是 "prependData",
  • sass-loader loader v10+, 这个选项名是 "additionalData",

11、pages

vue-cli3中的webpack与vue多页面应用开发
相关参数:

  • entry:page 的入口
  • template:模板来源
  • filename:在 dist/index.html 的输出
  • title:template 中的 title 标签需要是
  • chunks:在这个页面中包含的块,默认情况下会包含
module.exports = {
   pages:{
       main: {
           // page 的入口
           entry: "src/pages/main/main.js",
           // 模板来源
           template: "public/index.html",
           // 在 dist/index.html 的输出
           filename: "main.html",
           // 当使用 title 选项时,
           // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
           title: "Index Page",
           // 在这个页面中包含的块,默认情况下会包含
           // 提取出来的通用 chunk 和 vendor chunk。
           chunks: ["chunk-vendors", "chunk-common", "main"]
       },
       hh: {
           // page 的入口
           entry: "src/pages/login/main.js",
           // 模板来源
           template: "public/index.html",
           // 在 dist/index.html 的输出
           filename: "login.html",
           // 当使用 title 选项时,
           // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
           title: "Index Page",
           // 在这个页面中包含的块,默认情况下会包含
           // 提取出来的通用 chunk 和 vendor chunk。
           chunks: ["chunk-vendors", "chunk-common", "hh"]
       },
       // 当使用只有入口的字符串格式时,
       // 模板会被推导为 `public/subpage.html`
       // 并且如果找不到的话,就回退到 `public/index.html`。
       // 输出文件名会被推导为 `subpage.html`。
       subpage: "src/subpage/main.js"
   },
}

封装

const glob = require('glob') // 引入glob模块,用于扫描全部src/pages/**/main.js(返回的是一个数组)
// 打包多入口文件基本配置
function getPagesInfo() {
    let pages = {}

    glob.sync('src/pages/**/main.js').forEach((entry, i) => {
        let name = entry.slice(10, -8)
        pages[name] = {
            entry: entry,
            template: 'public.index.html',
            filename: name + '.html',
            title: '',
            chunks: ["chunk-vendors", "chunk-common", name]
        }
    })
    return pages
}
module.exports = {
    pages: getPagesInfo(),
    publicPath: './kk',
    assetsDir: 'static',
};

12、其他

  • parallel: require('os').cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
  • pwa: {}, // PWA 插件相关配置
  • pluginOptions: {} // 第三方插件配置

很好的pwa插件相关配置
pwa介绍及使用

二、优化

1、优化打包chunk-vendors.js

当运行项目并且打包的时候,会发现chunk-vendors.js这个文件非常大,那是因为webpack将所有的依赖全都压缩到了这个文件里面,这时我们可以将其拆分,将所有的依赖都打包成单独的js;

/*
利用splitChunks将每个依赖包单独打包,在生产环境下配置,代码如下
*/

configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置...
      config.mode = 'production'
      // 将每个依赖包打包成单独的js文件
      let optimization = {
        runtimeChunk: 'single',
        splitChunks: {
          chunks: 'all',
          maxInitialRequests: Infinity,
          minSize: 20000, // 依赖包超过20000bit将被单独打包
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name (module) {
                // get the name. E.g. node_modules/packageName/not/this/part.js
                // or node_modules/packageName
                const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]
                // npm package names are URL-safe, but some servers don't like @ symbols
                return `npm.${packageName.replace('@', '')}`
              }
            }
          }
        }
      }
      Object.assign(config, {
        optimization
      })
    } 
  }

2、打包时去除打印信息

上面已经提到过去掉打印的操作(console、debug)这里详细讲解一下

  1. 首先下载相关插件 uglifyjs-webpack-plugin

    npm i -D uglifyjs-webpack-plugin

  2. 在vue.config.js文件中引入,并在configureWebpack的optimization中添加如下代码

const UglifyPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
    
 configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置...
      config.mode = 'production'
      // 将每个依赖包打包成单独的js文件
      let optimization = {

        /*以下代码适用于uglifyjs-webpack-plugin 2.1.1及以前的版本*/
        minimizer: [new UglifyPlugin({
          uglifyOptions: {
            compress: {
              warnings: false,
              drop_console: true, // console
              drop_debugger: false,
              pure_funcs: ['console.log'] // 移除console
            }
          }
        })]
        
      }
      Object.assign(config, {
        optimization
      })
    }
   
  }
}

新版uglifyjs-webpack-plugin需写成以下方式

minimizer: [new UglifyPlugin({
    uglifyOptions: {
        warnings: false,
        compress: {
            drop_console: false, // console
            drop_debugger: false,
            pure_funcs: ['console.log'] // 移除console
        }
    }
})]

3、开启gizp压缩

gizp压缩是一种http请求优化方式,通过减少文件体积来提高加载速度。html、js、css文件甚至json数据都可以用它压缩,可以减小60%以上的体积。webpack在打包时可以借助 compression webpack plugin 实现gzip压缩。

  1. 下载 compression webpack plugin

    npm i -D compression-webpack-plugin

  2. vue.config.js配置

const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {

  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置...
      config.mode = 'production';

      if(openGzip){
        config.plugins = [
          ...config.plugins,
          new CompressionPlugin({
            test:/\.js$|\.html$|.\css/, //匹配文件名
            threshold: 10240,//对超过10k的数据压缩
            deleteOriginalAssets: false //不删除源文件
          })
        ]
      }

    } else {
      // 为开发环境修改配置...
      config.mode = 'development';
    }
    
  }
}
  1. package.js 配置
{
  "name": "demo-cli3",
  "version": "1.0.0",
  "openGizp": false,
  ...
}

4、vue-cli3 图片压缩【image-webpack-loader】使用

  1. 下载image-webpack-loader

    npm install --save-dev image-webpack-loader

  2. 在vue.config.js中修改相关配置
    4M的图片使用默认设置压缩成1.4M,自定义的设置可以更小

module.exports = {
  ...
  // 默认设置
  const defaultOptions = {
      bypassOnDebug: true
  }
 //  自定义设置
  const customOptions = {
      mozjpeg: {
        progressive: true,
        quality: 50
      },
      optipng: {
        enabled: true,
      },
      pngquant: {
        quality: [0.5, 0.65],
        speed: 4
      },
      gifsicle: {
        interlaced: false,
      },
      // 不支持WEBP就不要写这一项
      webp: {
        quality: 75
      }
  }
  chainWebpack: config => {

    config.module.rule('images') 
        .test(/\.(gif|png|jpe?g|svg)$/i)
        .use('image-webpack-loader')
        .loader('image-webpack-loader')
        .options(customOptions)
        .end() 

  }
}

5、移动端.px2rem 响应样式

  1. 安装

npm i -S lib-flexible postcss-px2rem

  1. 引入 lib-flexible

在项目入口中main.js 中引入lib-flexible

import 'lib-flexible' 

# 注意事项: 由于flexible会动态给页面header中添加<meta name='viewport' >标签,所以务必请把目录 public/index.html 中的这个标签删除!!
  1. 配置postcss-px2rem

项目中vue.config.js中进行如下的配置

module.exports = { 
    css: {
        loaderOptions: { 
            css: {}, 
            postcss: { 
                plugins: [ require('postcss-px2rem')({ remUnit: 37.5 }) 
                ] 
            } 
        } 
    } 
}

三、多页面应用开发与配置

搭建项目

1. 创建项目

和我们正常创建项目相同,这里通过vue-cli3脚手架进行创建

vue create 项目name
选择自己需要的依赖并进行下一步

2. 搭建文件结构

  • 新建pages存放每个页面相关内容
  • pages---下创建相关页面存放文件
  • 页面文件内放入main.js 与 router.js

3. 配置路由

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

// const originalPush = VueRouter.prototype.push
// VueRouter.prototype.push = function push(location) {
//   return originalPush.call(this, location).catch((err) => err)
// }
const routes = [
    {
        path: '/login',
        name: 'login',
        component: () => import('./views/index.vue'),
        // component:()=>import('./reset.vue'),
        meta: {
            title: '这里是动态title'
        },
        children: [

            /*  
            单页面应用的写法     
            {
                path: 'reset',
                name: 'reset',
                component: () => import('./reset.vue')
            
            },
            */
           
            //  ***多页面的写法
            {
                path: 'editJobs',
                components: {
                    'editJobs': () => import('./views/reset.vue'),
                },
            },],

    },
    // {
    //     path: '/',
    //     redirect: '/'
    // }

]
export default new VueRouter({
    mode: 'hash',
    base: process.env.BASE_URL,
    routes
})

4. 配置vue.config.js

// 打包多入口文件基本配置
function getPagesInfo() {
    let pages = {}
    const glob = require('glob') // 引入glob模块,用于扫描全部src/pages/**/main.js(返回的是一个数组)
    glob.sync('src/pages/**/main.js').forEach((entry, i) => {
        let name = entry.slice(10, -8)
        pages[name] = {
            entry: entry,
            template: 'public.index.html',
            filename: name + '.html',
            title: '',
            chunks: ["chunk-vendors", "chunk-common", name]
        }
    })
    return pages
}
module.exports = {
    pages: getPagesInfo(),
    publicPath: './kk',
    assetsDir: 'static',
};

注意事项

设置页面动态标题

  1. 下载 vue-wechat-title

npm i -S vue-wechat-title

  1. main.js中全局引入
import VueWechatTitle from 'vue-wechat-title'
Vue.use(VueWechatTitle)
  1. App.vue中设置
<template>
<!-- 动态设置title -->
  <div id="app" v-wechat-title='$route.meta.title'>
    <router-view/>
  </div>
</template>

路由子模块设置

  1. 路由配置方法
const routes = [
    {
        path: '/login',
        name: 'login',
        component: () => import('./views/index.vue'),
        meta: {
            title: '这里是动态title'
        },
        children: [
           
            //  ***多页面的写法
            {
                path: 'editJobs',
                components: {
                    'editJobs': () => import('./views/reset.vue'),
                },
            },],

    },
]
  1. 页面中渲染写法
<template>
  <div>
    login
    <router-link :to="{ name: 'reset' }" tag="li">我的收藏</router-link>
    这里的name对应的是route配置里的名字(别忘了地址连里面的path)
    <router-view name="editJobs">待完善信息</router-view>
  </div>
</template>

四、vue.config.js完整代码

// 打包多入口文件基本配置
let developmentPath = './';//开发环境-npm run serve时引用文件路径
let productionPath = './';//生产环境-npm run build打包后引用文件路径

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')//生产环境取消打印
const CompressionWebpackPlugin = require('compression-webpack-plugin')//gzip压缩

const productionGzipExtensions = ['js', 'css']
const Version = 'V6.1'
const Timestamp = new Date().getTime()
function getPagesInfo() {
    let pages = {}
    const glob = require('glob') // 引入glob模块,用于扫描全部src/pages/**/main.js(返回的是一个数组)
    glob.sync('src/pages/**/main.js').forEach((entry, i) => {
        let name = entry.slice(10, -8)
        pages[name] = {
            entry: entry,
            template: 'public.index.html',
            filename: name + '.html',
            title: '',
            chunks: ["chunk-vendors", "chunk-common", name]
        }
    })
    return pages
}
// 打包相关
module.exports = {
    pages: getPagesInfo(),//多页面应用配置
    publicPath: process.env.NODE_ENV === 'production' ? productionPath : developmentPath, // 基本路径-引用文件的路 __dirname + '/server/dist', //build之后静态文件输出路径
    assetsDir: 'static',//静态资源大包位置
    outputDir: __dirname + '/server/dist', //build之后静态文件输出路径
    lintOnSave: process.env.NODE_ENV !== 'production',// 打包的时候eslint-loader检查 
    productionSourceMap: false,//source map 检查
    // 启动服务器
    devServer: {
        index: '/login.html',   //默认打开文件
        open: true,             //自动打开浏览器
        host: 'localhost',      //默认打开域名
        port: 8080,             //默认打开端口号
        https: false,           //开启关闭https请求
        hotOnly: false,         //热更
        // 反向代理
        proxy: {
            // 配置跨域
            '/api': {
                target: 'http://dev.aabb.cn:8082/', //代理地址,这里设置的地址会代替axios中设置的baseURL
                ws: true,   //// proxy websockets
                changeOrigin: true,// 如果接口跨域,需要进行这个参数配置
                pathRewrite: {                //pathRewrite方法重写url
                    '^/api': '/',
                },
            },
        },
    },
    // webpack配置  链式
    chainWebpack: (config) => {
        // 1、取消预加载增加加载速度
        config.plugins.delete('preload')
        config.plugins.delete('prefetch')

        // 2、vue中使用SVG图标,并且想批量导入,然后需要使用的时候直接添加就可以
        config.module
            .rule('svg')
            .exclude.add(resolve('src/assets/icons'))
            .end()
        config.module
            .rule('icons')
            .test(/\.svg$/)
            .include.add(resolve('src/assets/icons'))
            .end()
            .use('svg-sprite-loader')
            .loader('svg-sprite-loader')
            .options({
                symbolId: 'icon-[name]',
            })
            .end()

        // 3、图片处理
        const imagesRule = config.module.rule('images')
        imagesRule.uses.clear() //清除原本的images loader配置
        imagesRule
            .test(/\.(jpg|gif|png|svg)$/)
            .exclude.add(path.join(__dirname, '../node_modules')) //不对node_modules里的图片转base64
            .end()
            .use('url-loader')
            .loader('url-loader')
            .options({ name: 'img/[name].[hash:8].[ext]', limit: 6000000 })

        config.optimization.splitChunks({
            cacheGroups: {

                vendors: {
                    name: 'chunk-vendors',
                    minChunks: pageNum,
                    test: /node_modules/,
                    priority: -10,
                    chunks: 'initial',
                },

                elementUI: {
                    name: 'chunk-elementUI', // split elementUI into a single package
                    priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                    test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
                },

                commons: {
                    name: 'chunk-commons',
                    test: resolve('src/components'), // can customize your rules
                    minChunks: 3, //  minimum common number
                    priority: 5,
                    reuseExistingChunk: true,
                },
            },
        })
    },
    // webpack配置
    configureWebpack: (config) => {
          // 为生产环境修改配置
        if (process.env.NODE_ENV === 'production') {
      
            config.plugins.push(
                  // 1、取消打印
                new UglifyJsPlugin({
                    uglifyOptions: {
                        compress: {
                            drop_debugger: true,//生产环境自动删除debugger
                            drop_console: true, //生产环境自动删除console
                        },
                        warnings: false,
                    },
                    sourceMap: false,   //关掉sourcemap 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
                    parallel: true, //使用多进程并行运行来提高构建速度。默认并发运行数:os.cpus().length - 1。
                }),

                // 2、gzip压缩
                new CompressionWebpackPlugin({
                    filename: '[path].gz[query]',
                    algorithm: 'gzip',
                    test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
                    threshold: 10240,
                    minRatio: 0.8,
                })
            )
        }

        // 在这里配置后,减少了压缩的包内容,需要在public/index.html通过cdn方式再引入,注意对应的版本
        config.externals = { 
            vue: 'Vue',
            'vue-router': 'VueRouter',
            vuex: 'Vuex',
            axios: 'axios',
            jquery: '$',
            moment: 'moment',
            'mint-ui': 'MINT'
        },


         // 别名配置
        Object.assign(config, {
            // 开发生产共同配置
            resolve: {
                alias: {
                '@': path.resolve(__dirname, './src'),
                '@c': path.resolve(__dirname, './src/components'),
                '@p': path.resolve(__dirname, './src/pages')
                }
            }
        }),

        config.output.filename = `[name].${Version}.${Timestamp}.js`  //打包生成的文件
        config.output.chunkFilename = `[name].${Version}.${Timestamp}.js`
    },
    // css相关
    css: {
        loaderOptions: {
            // 配置全局sass
            scss: {
                additionalData: `@import "@/assets/css/reset.scss";@import "@/assets/css/globle.scss";`  //注意配置的键名
            },
            // lib-flexible
            postcss: {
                plugins: [
                    //remUnit这个配置项的数值是多少呢??? 通常我们是根据设计图来定这个值,原因很简单,便于开发。
                    //假如设计图给的宽度是750,我们通常就会把remUnit设置为75,这样我们写样式时,可以直接按照设计图标注的宽高来1:1还原开发。
                    require('postcss-px2rem')({
                        remUnit: 37.5
                    })
                ]
            }
        }
    },
    parallel: require('os').cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
    pwa: {}, // PWA 插件相关配置 
    pluginOptions: {},  // 第三方插件配置
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容