Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从Highlight浅谈Webpack按需加载

从Highlight浅谈Webpack按需加载

作者头像
MrTreasure
发布于 2018-08-09 08:52:11
发布于 2018-08-09 08:52:11
2K00
代码可运行
举报
文章被收录于专栏:不止是前端不止是前端
运行总次数:0
代码可运行

动态加载CSS.gif

前言

最近有在使用 highlight.js 做代码的高亮展示,主要是展示对 SQL 语言的处理。看了看 highlight.js 的提供的相关代码

![2.png](https://upload-images.jianshu.io/upload_images/3995692-dc52856084af134e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

因为只需要加载对应语言的种类,以及一种样式,所以我们希望 webpack 能够按需加载

按需加载的实践

完全加载

为了对比出按需加载究竟能帮助我们节约多少资源,我们先贴出没有按需加载的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 忽略一些无关的代码
import * as hljs from 'highlight.js/lib/highlight'
import 'highlight.js/styles/atom-one-light.css'

export class Highlight extends React.Component {

  public componentDidMount() {
    hljs.highlightBlock((this.code as any))
  }

  public render() {
    return (
      <pre ref={ref => this.code = ref} style={{marginTop: 20}}>
        <code>{this.props.content}</code>
      </pre>
    )
  }
}

这是一份完整的加载,我们看看最后的数据有多大(包含完整引用的 antd 文件,我在项目中使用了 antd )

highlight-1.png

按需加载

接着我们按照官方的 demo 实现按需加载

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import * as hljs from 'highlight.js/lib/highlight'
import * as javascript from 'highlight.js/lib/languages/javascript'
hljs.registerLanguage('javascript', javascript)

其他的部分和上文相同,区别在于,没有从整个 highlight 中加载,而是引用了部分文件以及需要注册的 javascript 语言部分,默认是加载包含所有语言版本的 hljs ,看看这下的打包大小

highlight-2.png

我们可以看到,使用按需加载将近节省了600KB的空间,而使用按需加载的引入方式是 import * as XXX from 'module/lib/xxx'。并且使用 import { xx } from 'moduls' 并不能触发 webpack 的 treeshake,webpack仍然会打包完整库,哪怕引用的仅仅是从库里导出的接口(在ECharts下是如此表现的)。我们看看按需引用 antd 里的组件会是什么情况

部分按需引用

上面1.78MB的打包体积是 import { Card } from 'antd'(如gif效果图,我用Card包裹了高亮组件),接着我们看看

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import Card from 'antd/lib/card'

这种方式最后的打包体积

highlight-4.png

妈耶,居然这么小。

小结

  1. 如果要实现按需加载得使用babel-plugin-import,这个在TS下的情况还没有检查过
  2. 使用TS时,因为某些库的 d.ts 文件 指向的路径是模块,因此要导入该库的接口只能完整的导入该模块,比如ECharts,这个问题目前暂时还未解决

动态加载的实践

上面只是按需加载部分的JS,并且通过字符串写死的方式指定了路径,还有一部分,如同CSS的部分需要在组件生成时动态加载,或者通过变量的形式加载。如下所示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  constructor(props) {
    super(props)
    require('highlight.js/styles/' + this.props.css)
  }

  static async getDerivedStateFromProps(nextProps) {
    // const css = await import('highlight.js/styles/' + nextProps.css)
    const css = require('highlight.js/styles/' + nextProps.css)
    console.log(css)
    return null
  }

我们在构造阶段通过props传过来的变量加载对应的CSS文件,之前是使用import 'highlight.js/styles/atom-one-light.css'的方式,我们看看两者打包体积的区别

highlight-css-1.png

highlight-css-2.png

通过指定加载的CSS体积大小是427KB,而动态加载的体积大小是484KB。动态加载的体积要比静态加载的体积大很多。分析一下webpack打包的行为

webpack始终结合关键字并按照静态地址信息进行打包。比如require('highlight.js/styles/' + nextProps.css) require是关键字,接下来 webpack 会对 require 这个函数中的入参进行分析,它会发现入参有两个部分构成, 一部分是硬编码的 'highlight.js/styles/' 另一部分是不可知的变量。webpack将会以硬编码部分为打包入口,将'highlight.js/styles/*'下所有文件打包,在运行时根据完整的路径记载资源。

所以我们没办法使用完全的变量 require(variable),因为这样webpack找不到打包的路径。

缺陷

效果图虽然能看到我们通过 Select 的选择按需加载 CSS 样式,但其实是有缺陷的,表现为右侧可以看到,动态加载的CSS是通过一个个style标签加载上去的,这样后面的样式效果会覆盖前面的。表现为 当 Select 又选到已经加载的样式时, 浏览器并不会重新加载那段代码,导致样式无效。这个问题在另一个组件中得到了解决 react-syntax-highlighter

还没来得及看具体的实现,不过我估计应该是使用了 CSS-MODULES,明天再看看

没来得及验证的部分

有注意到 我在使用 const css = await import('xxx'),const css = require('xxx'),这两者的表现上是有区别的,前者是一个Promise对象,后者直接返回了值,这就涉及到了一个同步和异步的问题,虽然最后打印出来都是 {}, 不过这是因为没有使用CSS modules的原因。以后再研究研究 import require 动态加载时的区别

总结

  1. import { Card } from 'antd'并不会触发按需加载,仍然会加载全部antd文件,应该使用import Card from 'antd/lib/Card'
  2. 使用变量加载require('highlight.js/styles/' + this.props.style) webpack会打包 'highlight.js/styles/*'下所有文件
  3. 猜想 在TS下即使只从某个库里引用接口, import { IXxx } from 'xxx',webpack仍然会打包所有的 'xxx' 文件(在ECharts的表现下如此)

以上都是我瞎编的

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
​LeetCode刷题实战62:不同路径
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !
程序员小猿
2021/01/20
3220
​LeetCode刷题实战62:不同路径
【LeetCode】62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
韩旭051
2020/06/23
2500
【LeetCode】62. 不同路径
​LeetCode刷题实战63:不同路径 II
https://leetcode-cn.com/problems/unique-paths-ii/
程序员小猿
2021/01/20
2750
【算法】动态规划 ③ ( LeetCode 62.不同路径 | 问题分析 | 自顶向下的动态规划 | 自底向上的动态规划 )
LeetCode 62.不同路径 : https://leetcode.cn/problems/unique-paths
韩曙亮
2023/03/30
5870
【算法】动态规划 ③ ( LeetCode 62.不同路径 | 问题分析 | 自顶向下的动态规划 | 自底向上的动态规划 )
打卡群刷题总结0716——不同路径
链接:https://leetcode-cn.com/problems/unique-paths
木又AI帮
2020/07/20
2460
打卡群刷题总结0716——不同路径
DP(动态规划)经典路径问题 | LeetCode
动态规划中的路径问题,题目来自于 LeetCode,子标题为 题号 名称 的格式。
做棵大树
2022/09/27
5820
DP(动态规划)经典路径问题 | LeetCode
【leetcode刷题】T156-不同路径
https://leetcode-cn.com/problems/unique-paths/
木又AI帮
2019/09/03
2990
LeetCode 62. 不同路径(DP)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
Michael阿明
2021/02/20
2140
LeetCode 62. 不同路径(DP)
LeetCode 62. 不同路径 - Go 实现
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
王小明_HIT
2023/03/01
1590
LeetCode 62. 不同路径 - Go 实现
leetcode每日一题:62.不同路径
题目: https://leetcode-cn.com/problems/unique-paths/
用户3578099
2020/12/14
3210
09— 不同路径【LeetCode62】
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
吃猫的鱼Code
2023/07/24
2020
09— 不同路径【LeetCode62】
DP入门之不同路径
力扣题目链接:https://leetcode-cn.com/problems/unique-paths
代码随想录
2022/01/07
5250
DP入门之不同路径
leetcode刷题(123)——63. 不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
老马的编程之旅
2022/11/14
1900
leetcode刷题(123)——63. 不同路径 II
【leetcode刷题】T157-不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
木又AI帮
2019/09/03
3420
LeetCode 75 —— 62. 不同路径
示例 3: 输入:m = 7, n = 3 输出:28 示例 4: 输入:m = 3, n = 3 输出:6 提示: 1 <= m, n <= 100 题目数据保证答案小于等于 2 * 10^9 来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/unique-paths 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
Regan Yue
2023/07/10
1720
LeetCode 75 —— 62. 不同路径
LeetCode 63. 不同路径 II
拿到题目之后,这是一道考察动态规划的题。状态转移方程定义如下:dp[i][j] 表示 从起点到(i,j)位置所有路径。dp[i][j] = dp[i-1][j] + dp[i][j-1]。需要注意的是题目1表示障碍,则只有当前位置(i,j)为0时,才更新方程。而且在初始化dp数组的第1行和第1列时,dp[i][0], dp[0][j]为1。需要注意如果初始化过程中遇到障碍(i,j)为1时,则后续dp[i][0],dp[0][j] 设置为1。
用户7447819
2022/03/04
1990
【一天一大 lee】不同路径 (难度:中等) - Day20201209
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
前端小书童
2020/12/17
2940
打卡群刷题总结0717——不同路径 II
链接:https://leetcode-cn.com/problems/unique-paths-ii
木又AI帮
2020/07/22
2900
打卡群刷题总结0717——不同路径 II
62. 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
lucifer210
2019/10/21
3470
62. 不同路径
Leetcode No.63 不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
week
2021/05/06
4370
相关推荐
​LeetCode刷题实战62:不同路径
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验