美文网首页
【Webpack】Webpack核心原理

【Webpack】Webpack核心原理

作者: darkTi | 来源:发表于2022-04-25 16:59 被阅读0次

这篇主要就讲一下【打包】(bundle是打包,bundler是打包器)

现有问题

a.js.png
b.js.png
index.js.png

上面三个文件的代码都不能直接运行在浏览器中,因为浏览器不支持直接运行带有import和export关键字的代码,所以就引出了下面的问题

问题一:很多浏览器不认识import和export,只有现代浏览器(chrome、firefox、edge等),通过<script type="module" >来支持import和export;

问题二:虽然通过<script type="module" >可以支持import和export,但是不兼容IE8~15,而且可能会导致文件请求过多

平稳的兼容策略:把关键字转译成普通代码;且把所有文件打包成一个文件;
下面就来讲一下如何来实现上面这个策略

编译import和export关键字

项目中新增了bundler_1.ts,可以拿它和deps_4.ts做一下比较,看哪里做了改动;
主要添加了下面几行代码,通过babel把code转译一下:

 const { code: es5Code } = babel.transform(code, {
    presets: ['@babel/preset-env']
  })

运行一下,取其中的a.js的结果看一下:


image.png image.png

可以看出区别:
①import关键字没有了,变成了require;
②export关键字也没有了,变成了exports['default']
注意:这时这里的code是字符串

把所有代码打包成一个文件

那么这个文件应该是什么样的呢,首先它应该包含所有的模块,其次它还要可以执行所有的模块;
这时就有三个问题我们要来解决一下:
1、depRelation目前是对象,我们要把它变成数组(为什么变成数组呢,因为数组的第一项就是入口呀,而对象没有第一项这么一个概念);
2、code目前是字符串,我们要把它变成函数;
3、完善execude函数(execude函数就是用来执行入口文件的)

把depRelation从对象变成数组

引入bundler_2.ts,把它与bundler_1.ts做一下对比;node -r ts-node/register ./bundler_2.ts运行bundler_2.ts;

bundler_2.png bundler_1.png

把code从字符串变成函数

步骤
1、把code字符串外面包一个function(require, modules, exports){....};
2、再把这个code写到文件里,注意不要让引号出现在文件中;

完善execude函数

function execute(key) {
  // 如果已经 require 过,就直接返回上次的结果
  if (modules[key]) { return modules[key] }
  // 找到要执行的项目
  var item = depRelation.find(i => i.key === key)
  // 找不到就报错,中断执行
  if (!item) { throw new Error(`${item} is not found`) }
  // 把相对路径变成项目路径
  var pathToKey = (path) => {
    var dirname = key.substring(0, key.lastIndexOf('/') + 1)
    var projectPath = (dirname + path).replace(/\.\//g, '').replace(/\/\//, '/')
    return projectPath
  }
  // 创建 require 函数
  var require = (path) => {
    return execute(pathToKey(path))
  }
  // 初始化当前模块
  modules[key] = { __esModule: true }
  // 初始化 module 方便 code 往 module.exports 上添加属性
  var module = { exports: modules[key] }
  // 调用 code 函数,往 module.exports 上添加导出属性
  // 第二个参数 module 大部分时候是无用的,主要用于兼容旧代码
  item.code(require, module, module.exports)
  // 返回当前模块
  return modules[key]
}

手动构造dist.js文件

最后dist.js文件的主体结构应该如下

var depRelation = [
    {key: 'index.js', deps: ['a.js', 'b.js'], code: function...},
    {key: 'a.js', deps: ['b.js'], code: function...},
    {key: 'b.js', deps: ['a.js'], code: function...},
]
var modules = {}
execute(depRelation[0].key)
function execute(key){
  var require = ...
  var module = ...
  item.code(require, module, module.exports )
....

}

运行dist.js,可以得到和index.js一样的结果


dist.png

如何得到最终文件dist.js

我们已经知道了dist.js内容是什么了,但是该怎么去得到它呢,也就是说怎么自动生成dist.js文件呢?
答:拼凑出字符串,再把这些字符串写入到文件中即可,如下:

var code = ''
code += content
writeFileSync('dist.js', code)

编写bundler_3.ts,把它与bundler_2.ts做一下对比看哪里做了改动;bundler_3.ts就是打包器,可以自动生成最终文件,运行bundler_3.ts,得到dist_2.js(只是把名字变了下),node ./dist_2.js,得到结果与index.js一样;
并把我们通过打包器自动生成的dist_2.js与我们手动写出来的dist.js作对比,发现内容是一样的。
所以bundler_3.ts里的内容就是一个简易打包器,也就是webpack的核心内容!!

具体步骤

1、需要得到一个depRelation来收集依赖,它是一个数组,具体内容如下:

depRelation = [
    {key: 'index.js', deps: ['a.js', 'b.js'], code: `index.js代码内容的字符串`}, 
    {key: 'a.js', deps: ['b.js'], code: `a.js代码内容的字符串`},
    {key: 'b.js', deps: ['a.js'], code: `b.js代码内容的字符串`},
]

2、得到execude函数,函数具体内容可见上面,它接受一个参数,参数为depRelation[0].key,相当于depRelation[0].key(其实就是index.js)就是一个入口文件;

3、编写generateCode函数,它是打包器的核心,主要通过字符串拼接把我们手写出的dist.js里的内容,通过writeFileSync('dist2.js', generateCode())输出到指定文件里面去;这个过程中需要把depRelation中每一项中的code由字符串变成函数;

4、最后生成的dist2.js就是打包出来的文件啦;

不过目前这个简易打包器还有不少问题:
1、生成的代码中有不少重复的函数;
2、目前只能引入和运行JS文件;
3、只能理解import,无法理解require;
4、不支持插件;
5、不支持配置入口文件和dist的文件名;
但本篇文章主旨在于理解打包器是怎么打包的,所以这些问题后面一一再来梳理;

相关文章

  • 【Webpack】Webpack核心原理

    这篇主要就讲一下【打包】(bundle是打包,bundler是打包器) 现有问题 上面三个文件的代码都不能直接运行...

  • 前端知识体系4.前端工程化1.Webpack专题

    本文目录: 1.webpack的定义及基础核心概念 2.webpack构建原理 3.webpack运行的基本流程 ...

  • webpack - 项目优化

    Webpack学习笔记webpack - 项目优化webpack实现原理webpack - loaderwebpa...

  • webpack实现原理

    Webpack学习笔记webpack - 项目优化webpack实现原理webpack - loaderwebpa...

  • webpack - 项目优化2

    Webpack学习笔记webpack - 项目优化webpack实现原理webpack - loaderwebpa...

  • Webpack学习笔记

    Webpack学习笔记webpack - 项目优化webpack实现原理webpack - loaderwebpa...

  • webpack - loader

    Webpack学习笔记webpack - 项目优化webpack实现原理webpack - loaderwebpa...

  • webpack - plugin

    Webpack学习笔记webpack - 项目优化webpack实现原理webpack - loaderwebpa...

  • bunny笔记|手写webpack

    学习目标 了解webpack打包原理 了解webpack的loader原理 了解webpack的插件原理 了解as...

  • Webpack 核心原理

    webpack 要解决的两个问题 现有代码(接上文) 很遗憾,这三个文件不能运行因为浏览器不支持直接运行带有 im...

网友评论

      本文标题:【Webpack】Webpack核心原理

      本文链接:https://www.haomeiwen.com/subject/nvhoertx.html