webpack性能优化面面观

前言

开发中,webpack文件通常分为3个:css

  1. webpack.base.conf.js (基础文件)
  2. webpack.dev.conf.js (开发环境使用的webpack,须要与webpack.base.conf.js结合使用)
  3. webpack.prod.conf.js(上线环境使用的webpack,须要与webpack.base.conf.js结合使用)

一.优化构建速度

webpack在启动后,会根据Entry配置的入口,递归解析所依赖的文件。这个过程分为搜索文件把匹配的文件进行分析、转化的两个过程,所以能够从这两个角度来进行优化配置。html

1.1 缩小文件的搜索范围

搜索过程优化方式包括:

1. resolve字段告诉webpack怎么去搜索文件,因此首先要重视resolve字段的配置:

参考文档:webpack.docschina.org/configurati…node

resolve用来配置模块如何解析。例如,当在 ES2015 中调用 import 'lodash'resolve 选项可以对webpack 查找'lodash' 的方式去作修改(查看模块)。react

// webpack.config.js

module.exports = {
  //...
  resolve: {
    // configuration options
  }
};
复制代码
module.export = {
  resolve: {
    modules:[path.resolve(__dirname, 'node_modules')]
    extensions: ['.js', '.jsx'],
    mainFiles: ['index', 'child'],
    alias: {
       '@/src': path.resolve(__dirname, `../src`),  // 当看到@/src这个路径或字符串的时候,实际上指向的是../src目录
    }
  }
}
复制代码

(1). resolve.modules参考文档:www.webpackjs.com/configurati…jquery

resolve.modules告诉webpack解析时应该搜索的目录webpack

绝对路径和相对路径都能使用,可是要知道他们之间有一点差别。经过查看当前目录以及祖先路径(即 ./node_modules, ../node_modules 等等),相对路径将相似于 Node 查找 'node_modules' 的方式进行查找。使用绝对路径,将只在给定目录中搜索git

// webpack.config.js

module.exports = {
  //...
  resolve: {
    modules: ['node_modules'] // 相对路径写法,会按./node_modules, ../node_modules的方式查找
  }
};
复制代码

若是你想要添加一个目录到模块搜索目录,此目录优先于 node_modules/ 搜索:github

// webpack.config.js

module.exports = {
  //...
  resolve: {
    modules: [path.resolve(__dirname, 'src'), 'node_modules'] // 绝对路径写法
  }
};
复制代码

所以:设置resolve.modules:[path.resolve(__dirname, 'node_modules')]避免层层查找。 (2). resolve.mainFields参考文档: www.webpackjs.com/configurati…web

当从 npm包中导入模块时(例如,import * as D3 from "d3"),此选项将决定在 package.json 中使用哪一个字段导入模块。根据 webpack 配置中指定的 target 不一样,默认值也会有所不一样。ajax

target 属性设置为webworker, web 或者没有指定,默认值为:

module.exports = {
  //...
  resolve: {
    mainFields: ['browser', 'module', 'main']
  }
};
复制代码

对于其余任意的 target(包括 node),默认值为:

module.exports = {
  //...
  resolve: {
    mainFields: ['module', 'main']
  }
};
复制代码

例如,考虑任意一个名为 upstreamlibrary,其 package.json包含如下字段

{
  "browser": "build/upstream.js",
  "module": "index"
}
复制代码

在咱们 import * as Upstream from 'upstream' 时,这实际上会从browser 属性解析文件。在这里 browser属性是最优先选择的,由于它是 mainFields 的第一项。同时,由 webpack 打包的Node.js 应用程序首先会尝试从 module 字段中解析文件。

(3).resolve.alias参考文档:www.webpackjs.com/configurati…

建立 importrequire 的别名,来确保模块引入变得更简单。例如,一些位于 src/ 文件夹下的经常使用模块:

alias: {
  Utilities: path.resolve(__dirname, 'src/utilities/'),
  Templates: path.resolve(__dirname, 'src/templates/')
}
复制代码

如今,替换「在导入时使用相对路径」这种方式,就像这样:

import Utility from '../../utilities/utility';
复制代码

你能够这样使用别名:

import Utility from 'Utilities/utility';
复制代码

也能够在给定对象的键后的末尾添加 $,以表示精准匹配:

module.exports = {
  //...
  resolve: {
    alias: {
      xyz$: path.resolve(__dirname, 'path/to/file.js')
    }
  }
};
复制代码

这将产生如下结果:

import Test1 from 'xyz'; // 精确匹配,因此 path/to/file.js 被解析和导入
import Test2 from 'xyz/file.js'; // 非精确匹配,触发普通解析
复制代码

PS: 若是你使用了TS,在webpack中使用了resolve.alias,通常须要在tsconfig.json文件中对其进行配置,不然使用alias会致使没法找到响应目录而报错:

// tsconfig.json

"compilerOptions": {
    "paths": {
      "@/src/*": ["./src/*"],
      'Templates': ["./src/templates/"],
    },
}
复制代码

对庞大的第三方模块设置resolve.alias, 使webpack直接使用库的min文件,避免库内解析

(4). resolve.extensions参考文档:www.webpackjs.com/configurati…

配置resolve.extensions能够自动解析肯定的扩展。合理配置resolve.extensions,以减小文件查找

resolve.extensions默认值:extensions:['.wasm', '.mjs', '.js', '.json'],当导入语句没带文件后缀时,Webpack会根据extensions定义的后缀列表进行文件查找,因此:

  • 列表值尽可能少
  • 频率高的文件类型的后缀写在前面
  • 源码中的导入语句尽量的写上文件后缀,如require(./data)要写成require(./data.json)

经常使用写法:

extensions: ['.js', '.json', '.ts', '.tsx', '.scss']
复制代码

2. module.noParse字段告诉Webpack没必要解析哪些文件,能够用来排除对非模块化库文件的解析

参考文档:webpack.docschina.org/configurati…

jQuery、ChartJS,另外若是使用resolve.alias配置了react.min.js,则也应该排除解析,由于react.min.js通过构建,已是能够直接运行在浏览器的、非模块化的文件了。noParse值能够是RegExp、[RegExp]、function

module:{ noParse:[/jquery|chartjs/, /react\.min\.js$/]}
复制代码

3. 配置loader时,经过test、exclude、include等缩小搜索范围

{
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: `/fonts/[name].[hash:8].[ext]`
    }
}
复制代码

二.提高开发效率

开发过程当中修改代码后,须要自动构建和刷新浏览器,以查看效果。这个过程可使用Webpack实现自动化,Webpack负责监听文件的变化,DevServer负责刷新浏览器。

2.1 使用自动刷新

2.1.1 Webpack监听文件

Webpack能够开启监听: 启动webpack时加上--watch参数

webpack.js.org/configurati…

// package.json

"scripts": {
    "dev": "webpack --watch" // --watch监听打包文件,只要发生变化,就会从新打包。只要有这个参数就生效。
}
复制代码

但咱们想要更丰富的功能:执行npm run dev就会自动打包,并自动打开浏览器,同时能够模拟一些服务器上的特性,此时就要借助WebpackDevServer来实现。

devServer:{
    contentBase: './dist' // 服务器起在哪一个文件夹下。WebpackDevServer会帮助咱们在这个文件夹下起一个服务器
}
复制代码

配置

devServer:{
    port: 8080, // 默认8080
    contentBase: './dist',
    open: true, // 自动打开浏览器,并访问服务器地址。 file协议不行,不能发送ajax请求
    proxy: {
        './api': 'http://localhost:3000' // 用户访问 /api 这个路径会被转发到 http://localhost:3000,支持跨域代理
    }
}
复制代码

2.1.2 DevServer刷新浏览器

devServer: {
    contentBase: config.build.assetsRoot,
    host: config.dev.host,
    port: config.dev.port,
    open: true,
    inline: true,
    hot: true,
    overlay: {
      warnings: true,
      errors: true
    },
    historyApiFallback: {
      rewrites: [
        { from: /^\/index\//, to: `http://${config.dev.host}:${config.dev.port}/index.html` },
      ]
    },
    noInfo: true,
    disableHostCheck: true,
    proxy: {
      // '/user/message': {
      //   target: `http://go.buy.test.mi.com`,
      //   changeOrigin: true,
      //   secure: false
      // },
    }
  },
复制代码

DevServer刷新浏览器有两种方式:

  1. 向网页中注入代理客户端代码,经过客户端发起刷新
  2. 向网页装入一个iframe,经过刷新iframe实现刷新效果

默认状况下,以及 devserver: {inline:true} 都是采用第一种方式刷新页面。第一种方式DevServer由于不知道网页依赖哪些Chunk,因此会向每一个chunk中都注入客户端代码,当要输出不少chunk时,会致使构建变慢。而一个页面只须要一个客户端,因此关闭inline模式能够减小构建时间,chunk越多提高越明显。关闭方式:

  1. 启动时使用webpack-dev-server --inline false
  2. 配置devserver:{inline:false}

关闭inline后入口网址变为http://localhost:8080/webpack-dev-server/ 另外devServer.compress参数可配置是否采用Gzip压缩,默认为false

2.2 开启模块热替换HMR

模块热替换不刷新整个网页而只从新编译发生变化的模块,并用新模块替换老模块,因此预览反应更快,等待时间更少,同时不刷新页面能保留当前网页的运行状态。原理也是向每个chunk中注入代理客户端来链接DevServer和网页。开启方式:

webpack-dev-server --hot 使用HotModuleReplacementPlugin,比较麻烦

// package.json
"scripts": {
    "start": "webpack-dev-server" ,
}
复制代码

webpack-dev-server打包后的dist中的内容放到了内存中,加快访问速度

const webpack = require('webpack')

module.exports =  {
    devServer:{
        port: 8080, // 默认8080
        contentBase: './dist',
        open: true, 
        hot: true, // 让webpack-dev-server开启Hot Module Replacement功能
        hotOnly: true, // 即便HMR功能没有生效,也不让浏览器自动刷新,
    },
    module: {
        rules: [
        {
            test: /\.css$/,
            use:  [
                 'style-loader',
                 'css-loader',
                 'postcss-loader',
               ]
        },
        ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: 'src/index.html',
      }),
      new CleanWebpackPlugin(['dist']), // 开发环境不须要此配置
      new webpack.HotModuleReplacementPlugin() // 使用webpack插件,可用于开发环境
   ],
}
复制代码

开启后若是修改子模块就能够实现局部刷新,但若是修改的是根JS文件,会整页刷新,缘由在于,子模块更新时,事件一层层向上传递,直到某层的文件接收了当前变化的模块,而后执行回调函数。若是一层层向外抛直到最外层都没有文件接收,就会刷新整页。 使用 NamedModulesPlugin 可使控制台打印出被替换的模块的名称而非数字ID,另外同webpack监听,忽略node_modules目录的文件能够提高性能。

3、优化输出质量-压缩文件体积

3.1 区分环境--减少生产环境代码体积

代码运行环境分为开发环境生产环境,代码须要根据不一样环境作不一样的操做,许多第三方库中也有大量的根据开发环境判断的if else代码,构建也须要根据不一样环境输出不一样的代码,因此须要一套机制能够在源码中区分环境,区分环境以后可使输出的生产环境的代码体积减少。Webpack中使用DefinePlugin插件来定义配置文件适用的环境。

3.2 压缩代码-JS、CSS

1. 压缩JS:Webpack内置UglifyJS插件、ParallelUglifyPlugin

使用terser-webpack-plugin插件压缩JS代码: 参考文档: webpack.js.org/plugins/ter…

optimization: {
 minimizer: [
      new TerserPlugin({
        terserOptions: {
          safari10: true
        }
      })
    ],
}
复制代码

取代了 UglifyJsPlugin

// 取代 new UglifyJsPlugin(/* ... */)
复制代码

2. 压缩CSS

2.1 mini-css-extract-plugin:webpack.js.org/plugins/min… 。该插件将CSS提取到单独的文件中。它为每一个包含CSSJS文件建立一个CSS文件。它支持CSSSourceMap的按需加载。它基于新的webpack v4功能(模块类型)构建,而且须要webpack 4才能正常工做。

2.2 optimize-css-assets-webpack-plugin: www.npmjs.com/package/opt… 。主要是用来压缩css文件

plugins: [
    new MiniCssExtractPlugin({
      filename: path.join('css/[name].css?[contenthash:8]'),
      chunkFilename: path.join('css/[name].chunk.css?[contenthash:8]')
    }),
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css\?\w*$/
    })
],
复制代码

2.3 cssnano基于PostCSS,不只是删掉空格,还能理解代码含义,例如把color:#ff0000 转换成 color:redcss-loader内置了cssnano,只须要使用 css-loader?minimize 就能够开启cssnano压缩。 另一种压缩CSS的方式是使用PurifyCSSPlugin,须要配合 extract-text-webpack-plugin 使用,它主要的做用是能够去除没有用到的CSS代码,相似JSTree Shaking

3.3 使用Tree Shaking剔除JS死代码

参考文档:webpack.docschina.org/guides/tree…

Tree Shaking能够剔除用不上的死代码,它依赖ES6import、export的模块化语法,最早在Rollup中出现,Webpack 2.0将其引入。适合用于Lodash、utils.js等工具类较分散的文件。它正常工做的前提是代码必须采用ES6的模块化语法,由于ES6模块化语法是静态的(在导入、导出语句中的路径必须是静态字符串,且不能放入其余代码块中)。若是采用了ES5中的模块化,例如module.export = {...}、require( x+y )、if (x) { require( './util' ) },则Webpack没法分析出能够剔除哪些代码。

tree shaking 是一个术语,一般用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015模块语法的 静态结构 特性,例如importexport。这个术语和概念其实是由 ES2015 模块打包工具 rollup 普及起来的。

webpack 4正式版本扩展了此检测能力,经过package.json"sideEffects" 属性做为标记,向 compiler 提供提示,代表项目中的哪些文件是 "pure(纯的 ES2015 模块)",由此能够安全地删除文件中未使用的部分。

参考文档:webpack.docschina.org/guides/tree…

注意,全部导入文件都会受到tree shaking 的影响。这意味着,若是在项目中使用相似css-loaderimport 一个 CSS 文件,则须要将其添加到side effect列表中,以避免在生产模式中无心中将它删除:

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}
复制代码

参考文档:webpack.docschina.org/guides/tree…

经过 importexport语法,咱们已经找出须要删除的“未引用代码(dead code)”,然而,不只仅是要找出,还要在 bundle 中删除它们。为此,咱们须要将 mode配置选项设置为 production

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
- mode: 'development',
- optimization: {
-   usedExports: true
- }
+ mode: 'production'
};
复制代码
注意,也能够在命令行接口中使用 --optimize-minimize 标记,来启用 TerserPlugin。
复制代码

准备就绪后,而后运行另外一个 npm script npm run build,就会看到输出结果发生了改变。

dist/bundle.js 中,如今整个 bundle 都已经被 minify(压缩) 和 mangle(混淆破坏),可是若是仔细观察,则不会看到引入 square 函数,但能看到 cube函数的混淆破坏版本(function r(e){return e*e*e}n.a=r)。如今,随着 minification(代码压缩) 和tree shaking,咱们的bundle 减少几个字节!虽然,在这个特定示例中,可能看起来没有减小不少,可是,在有着复杂依赖树的大型应用程序上运行 tree shaking时,会对 bundle 产生显著的体积优化。

运行 tree shaking 须要 ModuleConcatenationPlugin。经过 mode: "production" 能够添加此插件。若是你没有使用 mode 设置,记得手动添加 ModuleConcatenationPlugin。
复制代码

参考文档:webpack.docschina.org/guides/tree…

结论: 咱们已经知道,想要使用 tree shaking 必须注意如下几点:

  • 使用 ES2015模块语法(即 importexport)。
  • 确保没有 compilerES2015 模块语法转换为 CommonJS模块(这也是流行的 Babel preset@babel/preset-env 的默认行为 - 更多详细信息请查看 文档)。
  • 在项目package.json 文件中,添加一个"sideEffects" 属性。
  • 经过将 mode选项设置为 production,启用 minification(代码压缩) 和tree shaking

你能够将应用程序想象成一棵树。绿色表示实际用到的 source code(源码)library(库),是树上活的树叶。灰色表示未引用代码,是秋天树上枯萎的树叶。为了除去死去的树叶,你必须摇动这棵树,使它们落下。

4、优化输出质量--加速网络请求

4.1 使用CDN加速静态资源加载

1. CND加速的原理

CDN经过将资源部署到世界各地,使得用户能够就近访问资源,加快访问速度。要接入CDN,须要把网页的静态资源上传到CDN服务上,在访问这些资源时,使用CDN服务提供的URL

因为CDN会为资源开启长时间的缓存,例如用户从CDN上获取了index.html,即便以后替换了CDN上的index.html,用户那边仍会在使用以前的版本直到缓存时间过时。业界作法:

  • HTML文件:放在本身的服务器上且关闭缓存,不接入CDN
  • 静态的JS、CSS、图片等资源:开启CDN和缓存,同时文件名带上由内容计算出的Hash值,这样只要内容变化hash就会变化,文件名就会变化,就会被从新下载而不论缓存时间多长。

另外,HTTP1.x版本的协议下,浏览器会对于向同一域名并行发起的请求数限制在4~8个。那么把全部静态资源放在同一域名下的CDN服务上就会遇到这种限制,因此能够把他们分散放在不一样的CDN服务上,例如JS文件放在js.cdn.com下,将CSS文件放在css.cdn.com下等。这样又会带来一个新的问题:增长了域名解析时间,这个能够经过dns-prefetch来解决 <link rel='dns-prefetch' href='//js.cdn.com'> 来缩减域名解析的时间。形如**//xx.com 这样的URL省略了协议**,这样作的好处是,浏览器在访问资源时会自动根据当前URL采用的模式来决定使用HTTP仍是HTTPS协议。

当浏览器从第三方服务跨域请求资源的时候,在浏览器发起请求以前,这个第三方的跨域域名须要被解析为一个IP地址,这个过程就是DNS解析,DNS缓存能够用来减小这个过程的耗时,DNS解析可能会增长请求的延迟,对于那些须要请求许多第三方的资源的网站而言,DNS解析的耗时延迟可能会大大下降网页加载性能。

参考文章: developer.mozilla.org/zh-CN/docs/…

2. 总之,构建须要知足如下几点:

  • 静态资源导入的URL要变成指向CDN服务的绝对路径的URL
  • 静态资源的文件名须要带上根据内容计算出的Hash
  • 不一样类型资源放在不一样域名的CDN

3. 最终配置:

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const {WebPlugin} = require('web-webpack-plugin');
//...
output:{
 filename: '[name]_[chunkhash:8].js',
 path: path.resolve(__dirname, 'dist'),
 publicPatch: '//js.cdn.com/id/', //指定存放JS文件的CDN地址
},
module:{
 rules:[{
     test: /\.css/,
     use: ExtractTextPlugin.extract({
         use: ['css-loader?minimize'],
         publicPatch: '//img.cdn.com/id/', //指定css文件中导入的图片等资源存放的cdn地址
     }),
 },{
    test: /\.png/,
    use: ['file-loader?name=[name]_[hash:8].[ext]'], //为输出的PNG文件名加上Hash值 
 }]
},
plugins:[
  new WebPlugin({
     template: './template.html',
     filename: 'index.html',
     stylePublicPath: '//css.cdn.com/id/', //指定存放CSS文件的CDN地址
  }),
 new ExtractTextPlugin({
     filename:`[name]_[contenthash:8].css`, //为输出的CSS文件加上Hash
 })
]

复制代码

4.2 多页面应用提取页面间公共代码,以利用缓存

  1. 原理

大型网站一般由多个页面组成,每一个页面都是一个独立的单页应用,多个页面间确定会依赖一样的样式文件、技术栈等。若是不把这些公共文件提取出来,那么每一个单页打包出来的chunk中都会包含公共代码,至关于要传输n份重复代码。若是把公共文件提取出一个文件,那么当用户访问了一个网页,加载了这个公共文件,再访问其余依赖公共文件的网页时,就直接使用文件在浏览器的缓存,这样公共文件就只用被传输一次。

  1. 应用方法

把多个页面依赖的公共代码提取到common.js中,此时common.js包含基础库的代码

把多个页面依赖的公共代码提取到common.js中,此时common.js包含基础库的代码
复制代码

找出依赖的基础库,写一个base.js文件,再与common.js提取公共代码到base中,common.js就剔除了基础库代码,而base.js保持不变

//base.js
import 'react';
import 'react-dom';
import './base.css';
//webpack.config.json
entry:{
    base: './base.js'
},
plugins:[
    new CommonsChunkPlugin({
        chunks:['base','common'],
        name:'base',
        //minChunks:2, 表示文件要被提取出来须要在指定的chunks中出现的最小次数,防止common.js中没有代码的状况
    })        
]
复制代码
  1. 获得基础库代码base.js,不含基础库的公共代码common.js,和页面各自的代码文件xx.js

页面引用顺序以下:base.js--> common.js--> xx.js

4.3 分割代码以按需加载

  1. 原理

单页应用的一个问题在于使用一个页面承载复杂的功能,要加载的文件体积很大,不进行优化的话会致使首屏加载时间过长,影响用户体验。作按需加载能够解决这个问题。具体方法以下:

  • 将网站功能按照相关程度划分红几类
  • 每一类合并成一个Chunk,按需加载对应的Chunk
  • 例如,只把首屏相关的功能放入执行入口所在的Chunk,这样首次加载少许的代码,其余代码要用到的时候再去加载。最好提早预估用户接下来的操做,提早加载对应代码,让用户感知不到网络加载
  1. 作法

一个最简单的例子:网页首次只加载main.js,网页展现一个按钮,点击按钮时加载分割出去的show.js,加载成功后执行show.js里的函数

//main.js
document.getElementById('btn').addEventListener('click',function(){
    import(/* webpackChunkName:"show" */ './show').then((show)=>{
        show('Webpack');
    })
})
//show.js
module.exports = function (content) {
    window.alert('Hello ' + content);
}

复制代码

import(/* webpackChunkName:show */ './show').then() 是实现按需加载的关键Webpack内置对import( *)语句的支持,Webpack会以./show.js为入口从新生成一个Chunk。代码在浏览器上运行时只有点击了按钮才会开始加载show.js,且import语句会返回一个Promise,加载成功后能够在then方法中获取加载的内容。这要求浏览器支持Promise API,对于不支持的浏览器,须要注入Promise polyfill/* webpackChunkName:show */ 是定义动态生成的Chunk的名称,默认名称是[id].js,定义名称方便调试代码。为了正确输出这个配置的ChunkName,还须要配置Webpack

//...
output:{
    filename:'[name].js',
    chunkFilename:'[name].js', // 指定动态生成的Chunk在输出时的文件名称
}
复制代码

5、优化输出质量--提高代码运行时的效率

5.1 使用Prepack提早求值

  1. 原理:

Prepack是一个部分求值器,编译代码时提早将计算结果放到编译后的代码中,而不是在代码运行时才去求值。经过在便一阶段预先执行源码来获得执行结果,再直接将运行结果输出以提高性能。可是如今Prepack还不够成熟,用于线上环境还为时过早。

参考文档:github.com/facebook/pr…

  1. 使用方法
const PrepackWebpackPlugin = require('prepack-webpack-plugin').default;
module.exports = {
    plugins:[
        new PrepackWebpackPlugin()
    ]
}
复制代码

5.2 使用Scope Hoisting

  1. 原理

译做“做用域提高”,是在Webpack3中推出的功能,它分析模块间的依赖关系,尽量将被打散的模块合并到一个函数中,但不能形成代码冗余,因此只有被引用一次的模块才能被合并。因为须要分析模块间的依赖关系,因此源码必须是采用了ES6模块化的,不然Webpack会降级处理不采用Scope Hoisting

  1. 使用方法
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
//...
plugins:[
    new ModuleConcatenationPlugin();
],
resolve:{
	mainFields:['jsnext:main','browser','main']
}
复制代码

webpack --display-optimization-bailout 输出日志中会提示哪一个文件致使了降级处理

6、使用输出分析工具

启动Webpack时带上这两个参数能够生成一个json文件,输出分析工具大多依赖该文件进行分析: webpack --profile --json > stats.json 其中 --profile 记录构建过程当中的耗时信息,--jsonJSON的格式输出构建结果,>stats.jsonUNIX / Linux系统中的管道命令,含义是将内容经过管道输出到stats.json文件中。

  1. 官方工具Webpack Analyse

打开该工具的官网http://webpack.github.io/analyse/上传stats.json,就能够获得分析结果

  1. webpack-bundle-analyzer

可视化分析工具,比Webapck Analyse更直观。使用也很简单:

npm i -g webpack-bundle-analyzer安装到全局 按照上面方法生成stats.json文件 在项目根目录执行webpack-bundle-analyzer,浏览器会自动打开结果分析页面。

相关文章
相关标签/搜索