前面的话

  前面介绍了webpack的基本配置,本文将详细介绍webpack中关于代码优化的配置

打包公共代码

  CommonsChunkPlugin 插件,是一个可选的用于建立一个独立文件(又称作 chunk)的功能,这个文件包括多个入口 chunk 的公共模块。通过将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,便存到缓存中供后续使用。这会带来速度上的提升,因为浏览器会迅速将公共的代码从缓存中取出来,而不是每次访问一个新页面时,再去加载一个更大的文件

  1. new webpack.optimize.CommonsChunkPlugin(options)

【配置项】

  1. {
  2. name: string, // or
  3. names: string[],
  4. // common chunk 的名称
  5. filename: string,
  6. // common chunk 的文件名模板。可以包含与 `output.filename` 相同的占位符
  7.  
  8. minChunks: number|Infinity|function(module, count) -> boolean,
  9. // 在传入公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks 。
  10. // 数量必须大于等于2,或者少于等于 chunks的数量
  11.  
  12. chunks: string[],
  13. // 通过 chunk name 去选择 chunks 的来源。chunk 必须是 公共chunk 的子模块。
  14. children: boolean,
  15. // 如果设置为 `true`,所有公共chunk 的子模块都会被选择
  16.  
  17. deepChildren: boolean,
  18. // If `true` all descendants of the commons chunk are selected
  19.  
  20. async: boolean|string,
  21. // 如果设置为 `true`,一个异步的公共chunk 会作为 `options.name` 的子模块,和 `options.chunks` 的兄弟模块被创建。
  22.  
  23. minSize: number,
  24. // 在 公共chunk 被创建立之前,所有公共模块 (common module) 的最少大小。
  25. }

【提取公共代码】

  1. new webpack.optimize.CommonsChunkPlugin({
  2. name: "commons",
  3. // ( 公共chunk(commnons chunk) 的名称)
  4.  
  5. filename: "commons.js",
  6. // ( 公共chunk 的文件名)
  7. })

【明确第三方库chunk】

  1. entry: {
  2. vendor: ["jquery", "other-lib"],
  3. app: "./entry"
  4. },
  5. plugins: [
  6. new webpack.optimize.CommonsChunkPlugin({
  7. name: "vendor",
  8. minChunks: Infinity,
  9. })
  10. ]

【将公共模块打包进父 chunk】

  1. new webpack.optimize.CommonsChunkPlugin({
  2. children: true,
  3. })

【额外的异步公共chunk】

  1. new webpack.optimize.CommonsChunkPlugin({
  2. name: "app",
  3. // or
  4. names: ["app", "subPageA"]
  5. children: true,
  6. async: true,
  7. minChunks: ,
  8. })

【wepack4】

  webpack 4 将移除 CommonsChunkPlugin, 取而代之的是两个新的配置项 optimization.splitChunks 和 optimization.runtimeChunk

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

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

  1. 当前模块是公共模块(多处引用)或者模块来自 node_modules
  2. 当前模块大小大于 30kb
  3. 如果此模块是按需加载,并行请求的最大数量小于等于
  4. 如果此模块在初始页面加载,并行请求的最大数量小于等于

  通过设置 optimization.runtimeChunk: true 来为每一个入口默认添加一个只包含 runtime 的 chunk

动态导入

  上面介绍的CommonsChunkPlugin可以去重和分离chunk。而本节介绍的动态导入,则是通过模块的内联函数调用来分离代码

  webpack 提供了两个类似的技术。对于动态导入,第一种,也是优先选择的方式是,使用符合 ECMAScript 提案 的 import() 语法。第二种,则是使用 webpack 特定的 require.ensure

  下面来使用import()语法来进行动态导入

  1. const path = require('path');
  2. const HTMLWebpackPlugin = require('html-webpack-plugin');
  3.  
  4. module.exports = {
  5. entry: {
  6. index: './src/index.js'
  7. },
  8. plugins: [
  9. new HTMLWebpackPlugin({
  10. title: 'Code Splitting'
  11. })
  12. ],
  13. output: {
  14. filename: '[name].bundle.js',
  15. chunkFilename: '[name].bundle.js',
  16. path: path.resolve(__dirname, 'dist')
  17. }
  18. };

  下面来动态导入loadsh

  1. function getComponent() {
     return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
  2. var element = document.createElement('div');
  3. element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  4. return element;
  5. }).catch(error => 'An error occurred while loading the component');
  6. } getComponent().then(component => {
  7. document.body.appendChild(component);
  8. })

  在注释中使用了 webpackChunkName。这样做会导致bundle 被命名为 lodash.bundle.js ,而不是 [id].bundle.js

懒加载

  懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载

  上面通过动态导入的loadsh确实会在脚本运行的时候产生一个分离的代码块 lodash.bundle.js ,在技术概念上“懒加载”它。问题是加载这个包并不需要用户的交互 -- 意思是每次加载页面的时候都会请求它

  下面来增加一个交互,当用户点击按钮的时候用 console 打印一些文字。但是会等到第一次交互的时候再加载那个代码块(print.js

  1. //print.js
  2. console.log('The print.js module has loaded! See the network tab in dev tools...');
  3. export default () => {
  4. console.log('Button Clicked: Here\'s "some text"!');
  5. }
  1. //index.js
  2. import _ from 'lodash';
  3. function component() {
  4. var element = document.createElement('div');
  5. var button = document.createElement('button');
  6. var br = document.createElement('br');
  7. button.innerHTML = 'Click me and look at the console!';
  8. element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  9. element.appendChild(br);
  10. element.appendChild(button);
  11. button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
  12. var print = module.default;
  13. print();
  14. });
  15. return element;
  16. }
  17. document.body.appendChild(component());

剔除无用代码

  tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup

【JS】

  JS的tree shaking主要通过uglifyjs插件来完成

  1. npm install --save-dev uglifyjs-webpack-plugin
  1. const path = require('path');
  2. const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
  3.  
  4. module.exports = {
  5. entry: './src/index.js',
  6. output: {
  7. filename: 'bundle.js',
  8. path: path.resolve(__dirname, 'dist')
  9. },
  10. plugins: [
  11. new UglifyJSPlugin()
  12. ]
  13. };

【CSS】

  CSS的tree shaking主要通过purify CSS来实现的

  1. npm i -D purifycss-webpack purify-css
  1. const path = require('path');
  2. const glob = require('glob');
  3. const ExtractTextPlugin = require('extract-text-webpack-plugin');
  4. const PurifyCSSPlugin = require('purifycss-webpack');
  5.  
  6. module.exports = {
  7. entry: {...},
  8. output: {...},
  9. module: {
  10. rules: [
  11. {
  12. test: /\.css$/,
  13. loader: ExtractTextPlugin.extract({
  14. fallbackLoader: 'style-loader',
  15. loader: 'css-loader'
  16. })
  17. }
  18. ]
  19. },
  20. plugins: [
  21. new ExtractTextPlugin('[name].[contenthash].css'),
  22. // Make sure this is after ExtractTextPlugin!
  23. new PurifyCSSPlugin({
  24. // Give paths to parse for rules. These should be absolute!
  25. paths: glob.sync(path.join(__dirname, 'app/*.html')),
  26. })
  27. ]
  28. };

  如果要设置多路径,则需要将glob换成glob-all

  1. const glob = require('glob-all');
  1. paths: glob.sync([
  2. path.join(__dirname, '.php'),
  3. path.join(__dirname, 'partials/.php')
  4. ])

模块热更新

  模块热更新,又称为模块热替换,HMR(Hot Module Replacement)。在应用程序运行过程中替换、添加或删除模块,无需重新加载页面,极大地加速了开发时间

  启用此功能实际上相当简单。而我们要做的,就是更新 webpack-dev-server 的配置,和使用 webpack 内置的 HMR 插件。此外,还添加了NamedModulesPlugin,以便更容易查看要修补(patch)的依赖

  1. const path = require('path');
  2. const HtmlWebpackPlugin = require('html-webpack-plugin');
  3. const CleanWebpackPlugin = require('clean-webpack-plugin');
  4. const webpack = require('webpack');
  5.  
  6. module.exports = {
  7. entry: {
  8. app: './src/index.js'
  9. },
  10. devtool: 'inline-source-map',
  11. devServer: {
  12. contentBase: './dist',
  13. hot: true
  14. },
  15. plugins: [
  16. new CleanWebpackPlugin(['dist']),
  17. new HtmlWebpackPlugin({
  18. title: 'Hot Module Replacement'
  19. }),
  20. new webpack.NamedModulesPlugin(),
  21. new webpack.HotModuleReplacementPlugin()
  22. ],
  23. output: {
  24. filename: '[name].bundle.js',
  25. path: path.resolve(__dirname, 'dist')
  26. }
  27. };

长缓存优化

【使用chunkhash】

  将hash替换为chunkhash,这样当chunk不变时,缓存依然有效

  1. const path = require('path');
  2. const CleanWebpackPlugin = require('clean-webpack-plugin');
  3. const HtmlWebpackPlugin = require('html-webpack-plugin');
  4.  
  5. module.exports = {
  6. entry: './src/index.js',
  7. plugins: [
  8. new CleanWebpackPlugin(['dist']),
  9. new HtmlWebpackPlugin({
  10. title: 'Caching'
  11. })
  12. ],
  13. output: {
  14. filename: '[name].[chunkhash].js',
  15. path: path.resolve(__dirname, 'dist')
  16. }
  17. };

【提取模板】

  CommonsChunkPlugin 可以用于将模块分离到单独的文件中。还能够在每次修改后的构建结果中,将 webpack 的样板(boilerplate)和 manifest 提取出来。通过指定 entry 配置中未用到的名称,此插件会自动将我们需要的内容提取到单独的包中

  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const CleanWebpackPlugin = require('clean-webpack-plugin');
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5.  
  6. module.exports = {
  7. entry: './src/index.js',
  8. plugins: [
  9. new CleanWebpackPlugin(['dist']),
  10. new HtmlWebpackPlugin({
  11. title: 'Caching'
  12. }),
  13. new webpack.optimize.CommonsChunkPlugin({
  14. name: 'manifest'
  15. })
  16. ],
  17. output: {
  18. filename: '[name].[chunkhash].js',
  19. path: path.resolve(__dirname, 'dist')
  20. }
  21. };

  将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用客户端的长效缓存机制,可以通过命中缓存来消除请求,并减少向服务器获取资源,同时还能保证客户端代码和服务器端代码版本一致。这可以通过使用新的 entry(入口) 起点,以及再额外配置一个 CommonsChunkPlugin 实例的组合方式来实现

  1. var path = require('path');
  2. const webpack = require('webpack');
  3. const CleanWebpackPlugin = require('clean-webpack-plugin');
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5.  
  6. module.exports = {
  7. entry: {
  8. main: './src/index.js',
  9. vendor: [
  10. 'lodash'
  11. ]
  12. },
  13. plugins: [
  14. new CleanWebpackPlugin(['dist']),
  15. new HtmlWebpackPlugin({
  16. title: 'Caching'
  17. }),
  18. new webpack.optimize.CommonsChunkPlugin({
  19. name: 'vendor'
  20. }),
  21. new webpack.optimize.CommonsChunkPlugin({
  22. name: 'manifest'
  23. })
  24. ],
  25. output: {
  26. filename: '[name].[chunkhash].js',
  27. path: path.resolve(__dirname, 'dist')
  28. }
  29. };

  [注意]CommonsChunkPlugin 的 'vendor' 实例,必须在 'manifest' 实例之前引入

【使用Name而不是id】

  每个 module.id 会基于默认的解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变

  下面来使用两个插件解决这个问题。第一个插件是 NamedModulesPlugin,将使用模块的路径,而不是数字标识符。虽然此插件有助于在开发过程中输出结果的可读性,然而执行时间会长一些。第二个选择是使用 HashedModuleIdsPlugin,推荐用于生产环境构建

  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const CleanWebpackPlugin = require('clean-webpack-plugin');
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5.  
  6. module.exports = {
  7. entry: {
  8. main: './src/index.js',
  9. vendor: [
  10. 'lodash'
  11. ]
  12. },
  13. plugins: [
  14. new CleanWebpackPlugin(['dist']),
  15. new HtmlWebpackPlugin({
  16. title: 'Caching'
  17. }),
  18. new webpack.HashedModuleIdsPlugin(),
  19. new webpack.optimize.CommonsChunkPlugin({
  20. name: 'vendor'
  21. }),
  22. new webpack.optimize.CommonsChunkPlugin({
  23. name: 'manifest'
  24. })
  25. ],
  26. output: {
  27. filename: '[name].[chunkhash].js',
  28. path: path.resolve(__dirname, 'dist')
  29. }
  30. };

公用代码内联

  使用html-webpack-inline-chunk-plugin插件将mainfest.js内联到html文件中

  1. $ npm install html-webpack-inline-chunk-plugin --save-dev
  1. const path = require('path');
  2. const webpack = require('webpack');
  3. const CleanWebpackPlugin = require('clean-webpack-plugin');
  4. const HtmlWebpackPlugin = require('html-webpack-plugin');
  5. const InlineChunkWebpackPlugin = require('html-webpack-inline-chunk-plugin');
  6.  
  7. module.exports = {
  8. entry: {
  9. main: './src/index.js',
  10. vendor: [
  11. 'lodash'
  12. ]
  13. },
  14. plugins: [
  15. new CleanWebpackPlugin(['dist']),
  16. new HtmlWebpackPlugin({
  17. title: 'Caching',
  18. inlineSource: '.(js|css)$'
  19. }),
  20. new webpack.HashedModuleIdsPlugin(),
  21. new webpack.optimize.CommonsChunkPlugin({
  22. name: 'vendor'
  23. }),
  24. new webpack.optimize.CommonsChunkPlugin({
  25. name: 'manifest'
  26. }),
  27. new InlineChunkWebpackPlugin({
  28. inlineChunks: ['manifest']
  29. })
  30. ],
  31. output: {
  32. filename: '[name].[chunkhash].js',
  33. path: path.resolve(__dirname, 'dist')
  34. }
  35. };

webpack配置之代码优化的更多相关文章

  1. [webpack] 配置react+es6开发环境

    写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...

  2. webpack配置详解

    webpack配置详解 先点个赞吧,再挨个点下面的连接,觉得不值这个赞的回来骂我啊. Webpack傻瓜式指南(一) Webpack傻瓜指南(二)开发和部署技巧 Webpack傻瓜式指南 原生的官网详 ...

  3. Webpack配置示例和详细说明

    /* * 请使用最新版本nodejs * 默认配置,是按生产环境的要求设置,也就是使用 webpack -p 命令就可以生成正式上线版本. * 也可以使用 webpack -d -w 命令,生成用于开 ...

  4. vue-cli#2.0 webpack 配置分析

    目录结构: ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-s ...

  5. webpack配置这一篇就够

    最近看了一篇好文,根据这个文章重新梳理了一遍webpack打包过程,以前的一些问题也都清楚了,在这里分享一下,同时自己也做了一些小的调整 原文链接:http://www.jianshu.com/p/4 ...

  6. webpack配置报错:invalid configuration object.webpack has been initialisted using a configuration objcet that does not match thie API schema

    最近接收了别人的项目,webpack配置总是报错如下:最后找到了解决办法,在此分享一下: 错误情况: 解决办法: 将package.json里面的colors删除掉即可

  7. 前端工程化(二)---webpack配置

    导航 前端工程化(一)---工程基础目录搭建 前端工程化(二)---webpack配置 前端工程化(三)---Vue的开发模式 前端工程化(四)---helloWord 继续上一遍的配置,本节主要记录 ...

  8. vue全家桶安装以及修改webpack配置新增vue项目启动方式

    一.安装node环境(自带npm) 下载地址 二.替换下载源 // 淘宝 NPM 镜像 npm install -g cnpm --registry=https://registry.npm.taob ...

  9. vue-cli中webpack配置详解

    vue-cli是构建vue单页应用的脚手架,命令行输入vue init <template-name> <project-name>从而自动生成的项目模板,比较常用的模板有we ...

随机推荐

  1. 浅谈SQL注入

    先看一个sql语句: select * from admin where username='(此处为用户输入的数据)'; 在没有任何过滤的情况下,如果用户输入:' or 1=1 -- 这条语句就为: ...

  2. 典型分布式系统分析:Bigtable

    本文是典型分布式系统分析的第三篇,分析的是Bigtable,一个结构化的分布式存储系统. Bigtable作为一个分布式存储系统,和其他分布式系统一样,需要保证可扩展.高可用与高性能.与此同时,Big ...

  3. 面试笔记--HashMap扩容机制

    转载请注明出处 http://www.cnblogs.com/yanzige/p/8392142.html 扩容必须满足两个条件: 1. 存放新值的时候当前已有元素的个数必须大于等于阈值 2. 存放新 ...

  4. Linux系统文件和目录管理

    Linux系统文件和目录管理 相关命令的解析 1.pwd:显示用户当前的工作目录 2.ls: -a:显示所有文件,包括隐藏文件 -l:显示文件的详细信息 3.设备文件统一存放在/dev 设备文件 块设 ...

  5. Maven之profile实现多环境配置动态切换

            一般的软件项目,在开发.测试及生产等环境下配置文件中参数是不同的.传统的做法是在项目部署的时候,手动修改或者替换这个配置文件.这样太麻烦了,我们可以用Maven的profile来解决这 ...

  6. 用Java执行Python:Jython踩坑笔记

    常见的java调用python脚本方式 1.通过Jython.jar提供的类库实现 2.通过Runtime.getRuntime()开启进程来执行脚本文件 1.Jython Jpython使用时,版本 ...

  7. docker部署nginx

    1. 下载nginx [root@localhost my.Shells]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/ ...

  8. 几种事务的隔离级别,InnoDB如何实现?

    事务ACID特性,其中I代表隔离性(Isolation). 什么是事务的隔离性? 隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离 ...

  9. lambda函数

    1.lambda函数是语法简短的匿名函数 2.lambda函数可以接受一个或多个参数 3.lambda函数只能有一个表达式 4.一般用于非重用的代码块 1)g = lambda x : x**2 g( ...

  10. Python 内置库 sys用法

    sys模块功能众多,这边先学习几个常用的方法sys常见函数列表① sys.argv: 实现从程序外部向程序传递参数.其实sys.argv[]就是一个列表,里面的项为用户输入的参数,但是sys.argv ...