手写一个webpack,看看AST怎么用

本文开始我会围绕webpack和babel写一系列的工程化文章,这两个工具我虽然天天用,但是对他们的原理理解的其实不是很深入,写这些文章的过程其实也是我深入学习的过程。由于webpack和babel的体系太大,知识点众多,不可能一篇文章囊括所有知识点,目前我的计划是从简单入手,先实现一个最简单的可以运行的webpack,然后再看看plugin, loader和tree shaking等功能。目前我计划会有这些文章:

手写最简webpack,也就是本文

webpack的plugin实现原理

webpack的loader实现原理

webpack的tree shaking实现原理

webpack的HMR实现原理

babel和ast原理

所有文章都是原理或者源码解析,欢迎关注~

本文可运行代码已经上传GitHub,大家可以拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/Engineering/mini-webpack

注意:本文主要讲webpack原理,在实现时并不严谨,而且只处理了import和export的default情况,如果你想在生产环境使用,请自己添加其他情况的处理和边界判断

为什么要用webpack

笔者刚开始做前端时,其实不知道什么webpack,也不懂模块化,都是html里面直接写script,引入jquery直接干。所以如果一个页面的JS需要依赖jquery和lodash,那html可能就长这样:

<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <script src="http://unpkg.com/jquery@3.5.1"></script> <script src="http://unpkg.com/lodash@4.17.20"></script> <script src="http://www.likecs.com/src/index.js"></script> </head> <body> </body> </html>

这样写会导致几个问题:

单独看index.js不能清晰的找到他到底依赖哪些外部库

script的顺序必须写正确,如果错了就会导致找不到依赖,直接报错

模块间通信困难,基本都靠往window上注入变量来暴露给外部

浏览器严格按照script标签来下载代码,有些没用到的代码也会下载下来

当前端规模变大,JS脚本会显得很杂乱,项目管理混乱

webpack的一个最基本的功能就是来解决上述的情况,允许在JS里面通过import或者require等关键字来显式申明依赖,可以引用第三方库,自己的JS代码间也可以相互引用,这样在实质上就实现了前端代码的模块化。由于历史问题,老版的JS并没有自己模块管理方案,所以社区提出了很多模块管理方案,比如ES2015的import,CommonJS的require,另外还有AMD,CMD等等。就目前我见到的情况来说,import因为已经成为ES2015标准,所以在客户端广泛使用,而require是Node.js的自带模块管理机制,也有很广泛的用途,而AMD和CMD的使用已经很少见了。

但是webpack作为一个开放的模块化工具,他是支持ES6,CommonJS和AMD等多种标准的,不同的模块化标准有不同的解析方法,本文只会讲ES6标准的import方案,这也是客户端JS使用最多的方案。

简单例子

按照业界惯例,我也用hello world作为一个简单的例子,但是我将这句话拆成了几部分,放到了不同的文件里面。

先来建一个hello.js,只导出一个简单的字符串:

const hello = 'hello'; export default hello;

然后再来一个helloWorld.js,将hello和world拼成一句话,并导出拼接的这个方法:

import hello from './hello'; const world = 'world'; const helloWorld = () => `${hello} ${world}`; export default helloWorld;

最后再来个index.js,将拼好的hello world插入到页面上去:

import helloWorld from "./helloWorld"; const helloWorldStr = helloWorld(); function component() { const element = document.createElement("div"); element.innerHTML = helloWorldStr; return element; } document.body.appendChild(component());

现在如果你直接在html里面引用index.js是不能运行成功的,因为大部分浏览器都不支持import这种模块导入。而webpack就是来解决这个问题的,它会将我们模块化的代码转换成浏览器认识的普通JS来执行。

引入webpack

我们印象中webpack的配置很多,很麻烦,但那是因为我们需要开启的功能很多,如果只是解析转换import,配置起来非常简单。

先把依赖装上吧,这没什么好说的:

// package.json { "devDependencies": { "webpack": "^5.4.0", "webpack-cli": "^4.2.0" }, }

为了使用方便,再加个build脚本吧:

// package.json { "scripts": { "build": "webpack" }, }

最后再简单写下webpack的配置文件就好了:

// webpack.config.js const path = require("path"); module.exports = { mode: "development", devtool: 'source-map', entry: "http://www.likecs.com/src/index.js", output: { filename: "http://www.likecs.com/main.js", path: path.resolve(__dirname, "dist"), }, };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxzpz.html