这些年,Webpack 基本成了前端项目打包构建的标配。关于它的原理和用法的文章在网上汗牛充栋,大家或多或少都看过一些。我也一样,大概了解过它的构建过程以及常用 loader 和 plugin 的配置、性能优化方法等等,仅限于“面试够用”的程度。在实际工作中,往往是配置好后就放一边了,没有遇到问题是不会再碰它的。

我一直有个习惯(或者叫毛病),就是不太愿意花时间去研究暂时用不上的技术。我称其为“屠龙之技”:学会了屠龙的技术,可是找不到龙啊。这样的技术没有实际应用来强化,过不了多久就会荒废的。也因为这个,之前面试吃过很多亏,毕竟由于平台所限,工作中根本接触不到某些方面的技术。不过话又说回来,为了面试也要去学,硬着头皮的那种。

扯远了,说回正题。前不久,网上有个哥们通过我的一篇博客找到我,让我帮他解决一个问题。这篇博客是关于如何在现有 Vue.js 项目里快速实现多语言切换的。他的项目也遇到同样的问题,但是他不懂代码,想付费求助。

按照我的方法,应该能很快完成需求。我大概估算了下工作量,报了个价。但是后面了解到的情况让我大跌眼镜:他的项目是打包好的,没有源码!说原来的开发不在了,都联系不上,找不到源码。要在没有源码的已有项目上加功能,写代码这么多年,还是第一次碰到。

我那篇文章的方案,是重写 Vue.prototype.__patch__ 方法,拦截 DOM 渲染过程,将翻译后的文本替换上去。面对一坨可读性极差的压缩代码,还怎么写下去?当时他还没付款,我本打算放弃了。直到晚上睡觉前,这个问题一直盘旋在脑海里,挥之不去。难道我的方案有这么大的局限性?很不服气啊!

没想到第二天,突然开窍了。这个问题的核心,不就是从压缩代码里找到 Vue 的引用吗?剩下的逻辑,都可以通过注入自己的 JS 代码来完成。

明确了这个思路,就开始了压缩代码挖掘之旅。我们都知道,Vue 项目在打包构建后,会在 HTML 文件里注入几个 JS 文件,大概像这样:

其中的 vendor.xxx.js 就包含了 Vue.js 框架代码。但我们知道,这样构建出来的代码肯定是用了闭包,各个模块都被作用域屏蔽了,window下是访问不到这些模块的。可以试试在控制台输入 Vue ,会提示 Uncaught ReferenceError: Vue is not defined

这个时候就需要研究 Webpack 是怎么打包的了。这里的关键在 manifest.js 文件,它是 Webpack 的运行时代码,定义了一个webpackJsonp函数,代码简化后是这样的:

(function(modules) {
window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
var moduleId, result;
for (moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
if (executeModules) {
for (i = 0; i < executeModules.length; i++) {
result = __webpack_require__(executeModules[i]);
}
}
return result;
};
var installedModules = {}; function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
return module.exports;
}
})([]);

打包后就是通过这个函数来加载各个模块的。因此,只要找到 Vue 这个模块被打包后的 ID,就能通过它来获取。再看看vendor.xxx.js这个文件内容:

webpackJsonp([38], {
"+abY": function(t, e, n) {
"use strict";
n("DmDj")("sup", function(t) {
return function() {
return t(this, "sup", "", "")
}
})
},
"+fX/": function(t, e, n) {
var r = n("awYD")
, i = n("JE6n")
, o = n("0U5H")("match");
t.exports = function(t) {
var e;
return r(t) && (void 0 !== (e = t[o]) ? !!e : "RegExp" == i(t))
}
},
"IvJb": function(t, e, n) {
// 这就是 Vue 框架代码
}
)

可以看到各个模块就是一个个的function。通过 Vue 框架里的一些关键字搜索,找到了 Vue 打包后的 ID 是IvJb。因此只要调用webpackJsonp函数就能获取 Vue变量:

var vue = webpackJsonp([], {}, ['IvJb']);
var __patch__ = vue.default.prototype.__patch__;
vue.default.prototype.__patch__ = function () {
var elm = __patch__.apply(this, arguments);
var lang = getUrlParam('lang')
if (lang) {
//翻译DOM里的文本
translate(elm, lang);
}
return elm;
};

关键问题解决了!通过同样的办法,还可以获取 axios ,把 axios baseUrl 改成了完整路径方便本地调试。剩下的工作就简单了,一是多语言文件文字翻译,那都是体力活,就交给那哥们自己干了。二是加一个语言切换菜单,这个也不难,原生 DOM 操作而已,再稍微调下样式就搞定了。

前前后后花了不到一天时间,完成了这个看似不可能的任务。由此可见,了解工具和框架的底层原理,对于解决特定问题有着决定性的作用。当然,Webpack 功能非常强大,底层逻辑比这里说的复杂多了,我也没有继续深入研究。或许下次碰到问题时又是一次契机。

关于多语言切换的方案,参考我之前写的博客:现有 Vue.js 项目快速实现多语言切换的一种思路

本文首发于公众号 1024译站

研究了一下 Webpack 打包原理,顺手挣了个 AirPods Pro的更多相关文章

  1. webpack打包原理

    什么是 webpack ? 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依 ...

  2. webpack构建原理和实现简单webpack

    webpack打包原理分析 基础配置,webpack会读取配置 (找到入口模块) 如:读取webpack.config.js配置文件: const path = require("path& ...

  3. Webpack 打包优化之速度篇

    在前文 Webpack 打包优化之体积篇中,对如何减小 Webpack 打包体积,做了些探讨:当然,那些法子对于打包速度的提升,也是大有裨益.然而,打包速度之于开发体验和及时构建,相当重要:所以有必要 ...

  4. Android 多渠道打包原理和使用

    每次中午吃饭总会和技术同学聊天.当做 iOS 开发的做安卓开发的人员在一起的时候,他们中间又多了一个话题:iOS 开发难还是安卓开发难. 这个时候做安卓开发的同学最激动说安卓开发要自己画界面.机型复杂 ...

  5. Webpack 打包之体积优化

    谈及如今欣欣向荣的前端圈,不仅有各类框架百花齐放,如Vue, React, Angular等等,就打包工具而言,发展也是如火如荼,百家争鸣:从早期的王者Browserify, Grunt,到后来赢得宝 ...

  6. 零基础学习webpack打包管理

    这些天在项目之余的时间学习了webpack打包项目的东西,非常荣幸的找到一些大神的文章来学习,死劲嚼了几天,终于略知一二.在以后的工作上还需继续学习,下面我将分享我这几天学到的一点东西,希望能让我一个 ...

  7. 使用webpack打包vue工程

    记得去年十月份的时候,自己在研究webpack,当时只是知道大致的用法,写了一个简单的demo,现在,经过了7个月对公司产品架构的使用,以及对vue-cli的使用,在了解了实际应用中各种需求之后,我自 ...

  8. webpack打包理解

    webpack打包理解(将所有依赖文件打包到一个文件中) 由于前端代码变得越来越多,越来越复杂, 纯粹脚本化的代码书写方式已经不能满足工程化得需求. 前端模块被抽象出来, 不仅仅包括js模块, 其它如 ...

  9. 提升webpack打包速度

    webpack打包文件体积过大,怎么提升速度? 借助webpack visualizer可视化插件,来看构建的情况.这个问题要具体情况具体分析,看看打包文件有哪些块头比较大,哪些不常改变,最好列一个l ...

随机推荐

  1. HihoCoder-1870 Jin Yong’s Wukong Ranking List(并查集)

    我发现大佬好像都是用拓扑排序写的(本菜鸡不会拓扑哭唧唧 说一下并查集的做法吧... 就是找两人右边的(辣鸡的那个人)那个是否比左边厉害,厉害的话就矛盾. 如果他俩没比较过就把厉害的并到辣鸡的. (辣鸡 ...

  2. Codeforces Round #550 (Div. 3) E. Median String (思维,模拟)

    题意:给你两个字符串\(s\)和\(t\),保证\(t\)的字典序大于\(s\),求他们字典序中间的字符串. 题解:我们假设题目给的不是字符串,而是两个10禁止的正整数,那么输出他们之间的数只要把他两 ...

  3. 51Nod - 1632

    B国拥有n个城市,其交通系统呈树状结构,即任意两个城市存在且仅存在一条交通线将其连接.A国是B国的敌国企图秘密发射导弹打击B国的交通线,现假设每条交通线都有50%的概率被炸毁,B国希望知道在被炸毁之后 ...

  4. Kubernetes安装EFK教程(非存储持久化方式部署)

    1.简介 这里所指的EFK是指:ElasticSearch,Fluentd,Kibana ElasticSearch Elasticsearch是一个基于Apache Lucene的开源搜索和数据分析 ...

  5. 使用DTK创建模糊背景窗口并自定义阴影效果

    DTK是deepin开发的基于Qt的开发套件,提供了大量的具有独特风格的美化控件,也提供了很多非常方便的API,下边我们用DTK实现一个模糊窗口,并设置其阴影效果. 使用场景 一切需要模糊窗口作为美化 ...

  6. 产品经理进阶:如何用UML的顺序图表达思想?

    当大家把UML建模语言下的各图形都有所了解后会发现,通过这些图可以全面的.立体的从各个角度表达产品,让产品的表达变得更丰富.更形象. "手中无剑.心中有剑",大多数产品人并不了解计 ...

  7. Semantic Pull Requests All In One

    Semantic Pull Requests All In One https://github.com/zeke/semantic-pull-requests docs: Update direct ...

  8. Web 前端如何一键开启上帝模式

    Web 前端如何一键开启上帝模式 God Mode document.designMode = `on`; refs https://www.cnblogs.com/xgqfrms/tag/desig ...

  9. GPU 加速 & WebGL

    GPU 加速 & WebGL 开启 GPU 加速, 硬件加速 垃圾面试官,瞎忽悠 holy shit 美国想象力英语,前端 leader WebGL 加速 ??? 是什么鬼 ??? three ...

  10. how to read the 10th line of a text using shell script

    how to read the 10th line of a text using shell script shell script / bash script question https://l ...