资讯专栏INFORMATION COLUMN

Webpack 最佳实践总结(二)

Stardustsky / 2689人阅读

摘要:默认做法是告诉浏览器这个文件的缓存时间,然后当文件内容被修改,则需要重命名该文件告诉浏览器需要重新下载和缓存,例如也能做类似的工作。

上一篇介绍了 Webpack 优化项目的四种技巧,分别是通过 UglifyJS 插件实现对 JavaScript 文件的压缩,css-loader 提供的压缩功能,配置NODE_ENV可以进一步去掉无用代码,tree-shaking帮助找到更多无用代码

这一篇主要讲 Webpack 的改进缓存(hash)、切割代码

使用 hash

开发过程经常需要一边预览代码运行结果一边修改代码,这个时候文件版本控制就显得尤为重要。默认做法是告诉浏览器这个文件的缓存时间,然后当文件内容被修改,则需要重命名该文件告诉浏览器需要重新下载和缓存,例如:


WebpackManifestPlugin 相比HtmlWebpackPlugin是一个更灵活的解决方案,尤其是面对复杂的服务端的部分。它能生成JSON文件,包含文件名以及与其对应(映射)的 hash 过的文件名

{
  "bundle.js": "bundle.8e0d62a03.js"
}

提示:Webpack的 hash 函数是不稳定的,这意味着在不同开发环境等条件下下,即便是同一个文件,webpack 依然会计算出不同的 hash 去标识这个相同的文件。正因为此,如果你有跨平台开发的需求,可以使用webpack-chunk-hash去代替webpack的原生的hash函数算法。更多关于 webpack hash 的问题可以查看:here

切割代码

想象一下你要开发一个大型网站,有首页和文章页,文章页里有文章内容和评论系统,但是你要将网站正常工作的代码都打包到一个文件里,这显然是不科学的。每次你修改其中一个模块,整改打包文件都要重新编译重新打包和生成,这意味着你仅仅只是修改一下评论模块,但当用户只访问首页,他们依然会下载这些暂时无用的代码,从而影响首页访问的加载速度

这个时候就需要切割打包文件,把它切割为首页和文章页所需的两个打包文件,当用用户访问首页时,只加载首页的打包文件,当访问文章页的时候,只加载文章页的打包文件,配置如下:

module.exports = {
  // 设置多个入口点,webpack给每个入口文件生成对应的打包文件
  // 从而实现不同页面加载不同的打包文件
  entry: {
    homepage: "./index.js",
    article: "./article.js"
  },
  output: {
    // [name]对应的是入口点的 name,如 homepage、article
    filename: "[name].[chunkhash].js"
  },
  plugins: [
    // 生成打包资源列表 json 文件
    new WebpackManifestPlugin(),
    // 取代 webpack 原生的 hash 函数
    new WebpackChunkHash(),
    // 生成依赖包的块文件,转移所有的`node_modules`依赖到一个特别的该文件中
    // 这允许你更新你的代码时,无需更新依赖
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      minChunks: m => m.context &&
        m.context.includes("node_modules"),
    }),
    // 生成 `webpack’s runtime` 自身的代码文件
    // 这允许你更新你的代码时,无需更新其他无关代码
    new webpack.optimize.CommonsChunkPlugin({
      name: "runtime",
      chunks: ["vendor"],
      minChunks: Infinity,
    }),
    // 标识每个模块 hash 值,当你添加新的模块时,如果该模块的依赖影响到别的模块
    // 就可以更新这些受影响的模块从而区分旧的模块
    new webpack.HashedModuleIdsPlugin(),
    // 生成资源映射文件,包含文件名以及与其对应的hash过的文件名,用于其他插件或者服务
    new ChunkManifestPlugin({
      filename: "chunk-manifest.json",
      manifestVariable: "webpackManifest"
    })
  ]
};

上面这个配置将会生成6个文件:

// 两个打包入口文文件,当你修改了业务代码,它们也会跟着变化
homepage.a68cd93e1a43281ecaf0.js
article.d07a1a5e55dbd86d572b.js

// 通用依赖文件与 webpack’s runtime 的文件,前者当你依赖包变化也跟着变化,后者极少变化,除非使用的 webpack 版本这类情况变化了才会跟着变化
vendor.1ebfd76d9dbc95deaed0.js
runtime.d41d8cd98f00b204e980.js

// 两个 manifest 文件,用于其他插件或服务,如 DllReferencePlugin
manifest.json
chunk-manifest.json
按需切割代码

除了按照不同页面的切割为不同的入口文件外的切割代码外,还可以按照构成页面的组件的顺序做到按需加载的去切割代码

想象一下,有一个页面布局方式如下所所示:

+-------------------------------+
| logo                    menu  |
+-------+----------------+------+
|       |                |      |
| left  |                | right|
| bar   |                | bar  |
|       |    article     |      |
|       |    content     |      |
|       |                |      |
|       |                |      |
|       +----------------+      |
|       |                |      |
|       |    comments    |      |
|       |                |      |
+-------+----------------+------+
|           copyright           |
+-------------------------------+

当访问这个页面时,用户希望首先能阅读到文章的内容,诸如其他评论、侧边栏等其他页面组成部分是可以被延后查看的。可惜的是,如果你将这些页面组成部分都打包到一个文件里,用户就需要等到整改打包文件加载后才能访问到他想要访问的内容

如何解决页面中各部分的按需加载?webpack 允许你做这方面的优化去实现代码的按需加载。首先你需要自己识别哪些代码是要首先加载的,然后 webpack 会移动需要延迟加载的代码到多带带的块中,只有在当需要这些被延迟加载的代码时,才会下载

假设有一个article-page.js业务代码文件,当你打包加载其会全部加载,包括文章内容、评论和侧边栏,如下:

// article-page.js
import { renderArticle } from "./components/article";
import { renderComments } from "./components/comments";
import { renderSidebar } from "./components/sidebar";

renderArticle();
renderComments();
renderSidebar();

做到按需加载则需要你将静态的import修改为动态的import(),webpack 会自带转移这些代码到多带带的块中,只有当被需要时才会加载,如下:

// article-page.js
import { renderArticle } from "./components/article";
renderArticle();

import("./comments.js")
  .then((module) => { module.renderComments(); });
import("./sidebar.js")
  .then((module) => { module.renderSidebar(); });

将静态的import修改为动态的import()的操作会带来提升首次访问时加载性能,同事也会优化缓存,当你更改这些业务代码时,只会修改对应的块文件,从而不影响其他块文件

当然,还需要重新设置 output ,如下:

// webpack.config.js
module.exports = {
  output: {
    filename: "[name].[chunkhash].js",
    chunkFilename: "[name].[chunkhash].js",
  }
};

output.chunkFilename可以标识按需加载的块文件

提示:当你使用默认的 presets 的 babel 去编译这些代码,你会得到一个语法错误提示:Babel don’t understand import() out of the box. 要避免这个错误,你需要给babel安装syntax-dynamic-import插件

externals

在一个大型项目中,如果有两段业务代码有共同的依赖,通过 webpack 的externals,你在两段代码间可以共享这些依赖,如下:

// webpack.config.js
module.exports = {
  externals: {
    "react": "React",
    "react-dom": "ReactDOM",
  }
};

上面的做法是将这些框架或库的对象挂靠在全局对象中,然后通过另外一个对象存储对象名以及映射到对应模块名的变量,webpack 就会替换所有所有模块下的相关的引用,然后你需要手动引入这些被externals的框架或库到网站入口文件中,如HtmlWebpackPlugin定义的template文件

总结

这次介绍如何通过 webpack 克服浏览器缓存打包文件,不去更新新的打包文件的问题,以及讲解了从不同的页面的角度去切割代码和从不同的页面组成部分去切割代码的过程,还有通过externals去分离去共有的框架和库,从而实现对这些框架或库的CDN资源加载

内容较多,大概就这样~

文章首发于:https://www.linpx.com/p/webpa...
欢迎访问我的博客:https://www.linpx.com

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87393.html

相关文章

  • Webpack 最佳实践总结(三)

    摘要:这里要介绍的是工作流中的一种很普遍的代码加工流程正常的业务逻辑开发流程需要经过预处理器如或,然后再经过后处理器如进行深加工。 还未看的,可以点击查看上两篇文章哟:Webpack 最佳实践总结(一)、Webpack 最佳实践总结(二) 好了,这篇是第三篇,也是完结篇,我感觉这一篇是最乱的一篇,凑合着看吧,不会让你失望的 整合 CSS 加工流 有时候,前端项目中除了 JavaScript ...

    pkhope 评论0 收藏0
  • Webpack 最佳实践总结(三)

    摘要:这里要介绍的是工作流中的一种很普遍的代码加工流程正常的业务逻辑开发流程需要经过预处理器如或,然后再经过后处理器如进行深加工。 还未看的,可以点击查看上两篇文章哟:Webpack 最佳实践总结(一)、Webpack 最佳实践总结(二) 好了,这篇是第三篇,也是完结篇,我感觉这一篇是最乱的一篇,凑合着看吧,不会让你失望的 整合 CSS 加工流 有时候,前端项目中除了 JavaScript ...

    jerryloveemily 评论0 收藏0
  • Vue开发总结 及 一些最佳实践 (已更新)

    摘要:基本开发环境创建的项目,作为代码编写工具插件推荐插件配置文章目录项目目录结构介绍框架选择处理请求二次封装项目目录结构简介业务相关静态文件全局组件基础样式布局样式及工具引入请求配置路由全局状态管理工具文件入口文件主要配置文件页面检查配置测试 基本开发环境 vue-cli3 创建的项目,vscode 作为代码编写工具vscode插件推荐:vscode 插件配置 文章目录 项目目录结构介绍...

    NotFound 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • Webpack 最佳实践总结(一)

    摘要:它会代替所有的实例的值为,从而使知道那些判断表达式总是错误的,从而删除相关代码,进一步压缩打包文件模块机制项目中使用的,通过也能通过打包有用的代码,进一步减少大小。 好久没写文章,这次预计会带来3篇的 Webpack 系列文章,将会在这几天内更新完。 Webpack3 自今年6月20日正式发布而来,给我们带来Scope Hoisting和Magic Comments两大功能,可惜不在这...

    jubincn 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<