webpack打包优化

webpack打包原理

把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元片段并按需加载。

webpack的优势

(1) webpack 是以 commonJS 的形式来书写脚本滴,但对 AMD/CMD 的支持也很全面,方便旧项目进行代码迁移。

(2)能被模块化的不仅仅是 JS 了。

(3) 开发便捷,能替代部分 grunt/gulp 的工作,比如打包、压缩混淆、图片转base64等。

(4)扩展性强,插件机制完善

webpack优化方法:

1.移除插件某些包,减少插件体积

比如说通用的日期库是moment.js,这个库会占用很大的体积,因为当引用这个库的时候,所有的locale文件都被引入,而这些文件甚至在整个库的体积中占了大部分, 要想对此进行优化必须在webpack打包时移除这部分内容

webpack自带的IgnorePlugin插件便会处理进行优化

plugins:[    
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]

2.模块化引入 按需导出

我们在引入lodash这种重型的js库的时候,我们可能只需要引用里面部分函数,但是当我们全部引入打包lodash.js体积就会很庞大

优化前

import _ from 'lodash';
 
console.log(_.map)
//ƒ map(collection,iteratee){var func=isArray(collection)?arrayMap:baseMap;return func(collection,getIteratee(iteratee,3));}

但是我们如果按需导入 这样就会减少很大体积

优化后

import map from 'lodash/map';
 
console.log(map)
//ƒ map(collection, iteratee) {
  var func = isArray(collection) ? arrayMap : baseMap;
  return func(collection, baseIteratee(iteratee, 3));
}

3.优化resolve.extensions配置 设置解析文件后缀

设置解析文件后缀,可以加速文件寻找速度

resolve: {
    extensions: ['.js', '.json', 'jsx']
}

4.优化resolve.modules配置

resolve.modules 用于配置Webpack去哪些目录下寻找第三方模块。resolve.modules的默认值是[node modules],含义是先去当前目录的/node modules目录下去找我们想找的模块,如果没找到,就去上一级目录…/node modules中找,再没有就去…/ … /node modules中找,以此类推,这和Node.js的模块寻找机制很相似。当安装的第三方模块都放在项目根目录的./node modules目录下时,就没有必要按照默认的方式去一层层地寻找,可以指明存放第三方模块的绝对路径,以减少寻找。

resolve: {
    // 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
    modules: [path.resolve(__dirname,'node_modules')]
}

5.优化loader配置 缩小文件搜索范围

由于Loader对文件的转换操作很耗时,所以需要让尽可能少的文件被Loader处理。我们可以通过以下3方面优化Loader配置:
(1)优化正则匹配
(2)通过cacheDirectory选项开启缓存
(3)通过include、exclude来减少被处理的文件。

module: {
    rules: [
        {
            test:/\.js$/,
            //babel-loader支持缓存转换出的结果,通过cacheDirectory选项开启
            loader:'babel-loader?cacheDirectory',
            //只对项目根目录下的src 目录中的文件采用 babel-loader
            include: [path.resolve('src')],
            //排除 node_modules 目录下的文件,node_modules 目录下的文件都是采用的 ES5 语法,没必要再通过 Babel 去转换
            exclude: path.resolve(__dirname, 'node_modules')
        }
    ]
}

6.optimization.splitChunks 提取公共代码

Webpack 4 移除了 CommonsChunkPlugin取而代之的是两个新的配置项 optimization.splitChunks 和 optimization.runtimeChunk。

CommonsChunkPlugin

webpack 将多个模块打包之后的代码集合称为 chunk。为了将一些很少变化的常用库(react、redux、lodash)与业务代码分开,或者是一些不同入口共同使用的公共模块,开发者常常需要将它们单独打包,这些都可以通过配置 CommonsChunkPlugin 来实现。

entry: {
    app:'./main.js',
    vendor: ['react','react-dom']
},
plugins:
    new webpack.optimize.CommonsChunkPlugin({names:['vendor']})
]

webpack 4 准备通过 optimization.splitChunks 和 optimization.runtimeChunk 属性来简化代码分割的配置

optimization.splitChunks

通过设置 optimization.splitChunks.chunks: “all” 来启动默认的代码分割配置项。

当满足如下条件时,webpack 会自动打包 chunks:

1)当前模块是公共模块(多处引用)或者模块来自 node_modules

2)当前模块大小大于 30kb 如果此模块是按需加载,并行请求的最大数量小于等于 5

3)如果此模块在初始页面加载,并行请求的最大数量小于等于 3

optimization: {
    splitChunks: {
        chunks: 'all',
        name: true,
        automaticNameDelimiter: '-',  // 模块间的连接符,默认为"~"
        cacheGroups: {
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                priority: -10  // 优先级,越小优先级越高
            },
            default: {  // 默认设置,可被重写
                minChunks: 2,
                priority: -20,
                reuseExistingChunk: true  // 如果本来已经把代码提取出来,则重用存在的而不是重新产生
            }
        }
    }
}

7.用 Happypack 来加速代码构建

由于有大量文件需要解析和处理,构建是文件读写和计算密集型的操作,特别是当文件数量变多后,Webpack 构建慢的问题会显得严重。
运行在 Node.js 之上的 Webpack 是单线程模型的,也就是说 Webpack 需要处理的任务需要一件件挨着做,不能多个事情一起做。 文件读写和计算操作是无法避免的,那能不能让 Webpack 同一时刻处理多个任务,HappyPack 就能让 Webpack 做到这点,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
当同时读取多个loader文件资源时,比如`babel-loader`需要 transform 各种jsx,es6的资源文件。在这种同步计算同时需要大量耗费 cpu 运算的过程中,node的单进程模型就无优势了,而 Happypack 就是针对解决此类问题而生的存在

const HappyPack = require('happypack');
module: {    rules: [
        {
            test:/\.js/,
            //loader:'babel-loader',
            include: [path.resolve('src')],
            // 排除 node_modules 目录下的文件,node_modules 目录下的文件都是采用的 ES5 语法,没必要再通过 Babel 去转换
            exclude: path.resolve(__dirname, 'node_modules'),
            // 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
            loader: 'happypack/loader?id=babel'
        }
    ]
},
plugins:[    new HappyPack({
        // 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
        id: 'babel',
        // 如何处理 .js 文件,用法和 Loader 配置中一样
        loaders: ['babel-loader?cacheDirectory'],
        // ... 其它配置项
    })
]
 

8. 使用CDN 加速优化

cdn优化是指把第三方库比如(vue,vue-router,axios)通过cdn的方式引入项目中,这样vendor.js会显著减少,并且大大提升项目的首页加载速度,下面是具体操作:

onst isProduction = process.env.NODE_ENV === 'production';

// externals
const externals = {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  vuex: 'Vuex',
  vant: 'vant',
  axios: 'axios'
}
// CDN外链,会插入到index.html中
const cdn = {
  // 开发环境
  dev: {
    css: [],
    js: []
  },
 // 生产环境
  build: {
    css: ['https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css'],
    js: [
      'https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.min.js',
      'https://cdn.jsdelivr.net/npm/vue-router@3.1.5/dist/vue-router.min.js',
      'https://cdn.jsdelivr.net/npm/axios@0.19.2/dist/axios.min.js',
      'https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.min.js',
      'https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js'
    ]
  }
}
module.exports = {
  configureWebpack: config => {
    // 为生产环境修改配置...
    if (isProduction) {
      // externals
      config.externals = externals
    }
  },
  chainWebpack: config => {
    /**
     * 添加CDN参数到htmlWebpackPlugin配置中
     */
    config.plugin('html').tap(args => {
      if (isProduction) {
        args[0].cdn = cdn.build
      } else {
        args[0].cdn = cdn.dev
      }
      return args
    })
  }
}

在 public/index.html 中添加

  <!-- 使用CDN的CSS文件 -->
    <% for (var i in
      htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
      <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
    <% } %>
     <!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
    <% for (var i in
      htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
      <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>

总结:配置了cdn引入,1.1M体积较少到660kb。效果很明显。

相关面试题

  • Webpack和grunt和gulp有啥不同:

Webpack是一个模块打包器,grunt和gulp是执行任务的,webpack可以递归的打包项目中的所有模块(递归:指定一个入口,分析模块的依赖,它会递归的查找所有相关的依赖),最终生成几个打包后的文件,他和其他的工具的最大的不同在于它支持code-splitting(代码分割),模块化(AMD,ESM,CommonJS)开发,全局的分析工具(分析整个项目引入的模块)

  • 什么是bundle,什么是chunk,什么是module:

bundle是由webpack打包出来的文件,chunk是指webpack在进行模块依赖分析的时候,代码分割出来的代码块,module是开发中的单个模块

  • 什么是loader,什么是plugin:

loader是用来告诉webpack如何转化处理某一类型的文件,并且引入到打包出的文件中
plugin是用来自定义webpack打包过程中的方式,一个插件是含有apply方法的一个对象,通过这个方法可以参与到整个webpack打包的各个流程(生命周期)

  • webpack-dev-server和http服务器如nginx有什么不同:

webpack-dev-server使用内存来存储webpack开发环境下的打包文件,并且可以使用模块热更新,他比传统的http服务器对开发更加简单高效

  • 什么是模块热更新,优点:

模块热更新是webpack的一个功能,他可以使得代码修改过后不用刷新浏览器就可以更新,是高级版的自动刷新浏览器(将代码重新执行而不整体刷新浏览器)
只更新变更内容,以节省宝贵的开发时间。调整样式更加快速,几乎相当于在浏览器中更改样式

  • 优化问题

在这里插入图片描述

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值