python模块捆绑器组件

by Adam Kelly

通过亚当凯利

让我们学习模块捆绑器如何工作,然后自己编写 (Let’s learn how module bundlers work and then write one ourselves)

Hello! Welcome, welcome, it’s great to have you here! Today we’re going to be building a really simple JavaScript module bundler.

你好! 欢迎,欢迎,很高兴你在这里! 今天,我们将构建一个非常简单JavaScript模块捆绑器。

Before we start, I want to give a few acknowledgements. This article draws heavily on the following resources:

在开始之前,我想先说几句。 本文主要利用以下资源:

  • Unbundling the JavaScript module bundler - Luciano Mammino

    取消捆绑JavaScript模块捆绑器 -Luciano Mammino

  • Minipack - Ronen Amiel

    迷你包装 -罗恩·阿米尔(Ronen Amiel)

Okay, lets get started with what a module bundler actually is.

好的,让我们开始了解模块捆绑器的实际含义。

什么是模块捆绑器? (What’s A Module Bundler?)

A module bundler is a tool that takes pieces of JavaScript and their dependencies and bundles them into a single file, usually for use in the browser. You may have used tools such as Browserify, Webpack, Rollup or one of many others.

模块捆绑器是一种工具,用于获取JavaScript片段及其相关性,并将其捆绑到一个文件中,通常在浏览器中使用。 您可能使用过诸如Browserify , Webpack , Rollup或其他工具之一。

It usually starts with an entry file, and from there it bundles up all of the code needed for that entry file.

它通常从一个入口文件开始,然后从那里捆绑该入口文件所需的所有代码。

There are two main stages of a bundler:

捆绑器有两个主要阶段:

  1. Dependency resolution依赖解析
  2. Packing填料

Starting from an entry point (such as app.js above), the goal of dependency resolution is to look for all of the dependencies of your code (other pieces of code that it needs to function) and construct a graph (called a dependency graph).

从入口点(例如上面的app.js )开始,依赖关系解析的目标是查找代码的所有依赖关系(它需要运行的其他代码段)并构建图(称为依赖关系图) )。

Once this is done, you can then pack or convert your dependency graph into a single file that the application can use.

完成此操作后,您可以将依赖关系图打包或转换为应用程序可以使用的单个文件。

Let’s start out our code with some imports (I’ll elaborate on the reason later).

让我们从一些导入开始我们的代码(稍后将详细说明原因)。

依赖解决 (Dependency Resolution)

The first thing we have to do is think up how we want to represent a module during the dependency resolution phase.

我们要做的第一件事是思考在依赖关系解析阶段如何表示模块。

模块表示 (Module Representation)

We are going to need four things:

我们将需要四件事:

  • The name and an identifier of the file文件的名称和标识符
  • Where the file came from (in the file system)文件的来源(在文件系统中)
  • The code in the file文件中的代码
  • What dependencies that file needs该文件需要什么依赖

The graph structure gets built up through recursively checking for dependencies within each file.

通过递归检查每个文件中的依赖关系来建立图结构。

In JavaScript, the easiest way to represent such a set of data would be an object.

在JavaScript中,表示这样一组数据的最简单方法是对象。

Looking at the createModuleObject function above, the notable part is the call to a function called detective.

查看上面的createModuleObject函数,值得注意的部分是对名为detective的函数的调用。

Detective is a library that can find all calls to require() no matter how deeply nested, and using it means we can avoid doing our own AST traversal!

侦探是可以找到所有的呼叫需要()无论多么深的嵌套一库,并利用它意味着我们能够避免做我们自己的AST穿越!

One thing to note (and this is the same in almost all module bundlers) is that if you try to do something weird like:

需要注意的一件事(几乎在所有模块捆绑器中都一样)是,如果您尝试做一些奇怪的事情,例如:

const libName = 'lodash'const lib = require(libName)

It will not be able to find it (because that would mean executing the code).

它将无法找到它(因为这意味着执行代码)。

So what does running this function from the path of a module give?

那么从模块的路径运行此功能会带来什么呢?

Whats next? Dependency resolution.

下一步是什么? 依赖性解析。

Okay, not quite yet. First, I want to talk about a thing called a module map.

好的,还没有。 首先,我想谈一谈称为模块映射的事情。

模块图 (Module Map)

When you import modules in Node, you can do relative imports, like require('./utils'). So when your code calls this, how does the bundler know what is the right ./utils file when everything is packaged?

在Node中导入模块时,可以进行相对导入,例如require('./utils') 。 因此,当您的代码调用此代码时,打包所有内容后,捆绑程序如何知道正确的./utils文件?

That is the problem the module map solves.

那就是模块图解决的问题。

Our module object has a unique id key which will be our ‘source of truth’. So when we are doing our dependency resolution, for each module, we will keep a list of the names of what is being required along with their id. This way, we can get the correct module at run-time.

我们的模块对象具有唯一的id密钥,它将作为我们的“真理之源”。 因此,当我们进行依赖关系解析时,对于每个模块,我们将保留所需内容的名称及其ID的列表。 这样,我们可以在运行时获取正确的模块。

This also means that we can store all of the modules in a non-nested object, using the id as a key.

这也意味着我们可以使用id作为键将所有模块存储在非嵌套对象中。

依赖解决 (Dependency Resolution)

Okay, so there is a fair amount going on in the getModules function. Its main purpose is to start at the root/entry module, and look for and resolve dependencies recursively.

好的,因此getModules函数中发生了很多事情。 它的主要目的是从root / entry模块开始,并递归查找和解决依赖关系。

What do I mean by ‘resolve dependencies’? In Node there is a thing called the require.resolve, and it’s how Node figures out where the file that you are requiring is. This is because we can import relatively or from a node_modules folder.

“解决依赖关系”是什么意思? 在Node中,有一个叫做require.resolve的东西,这就是Node找出您需要的文件的位置的方式。 这是因为我们可以相对导入,也可以从node_modules文件夹导入。

Lucky for us, there’s an npm module named resolve which implements this algorithm for us. We just have to pass in the dependency and base URL arguments, and it will do all the hard work for us.

对我们来说幸运的是,有一个名为resolve的npm模块为我们实现了该算法。 我们只需要传递依赖项和基本URL参数,它将为我们完成所有艰苦的工作。

We need to carry out this resolution for each dependency of each module in the project.

我们需要对项目中每个模块的每个依赖项执行此解决方案。

We are also creating the module map named map that I mentioned earlier.

我们还将创建我前面提到的名为map的模块映射。

At the end of the function, we are left with an array named modules which will contain module objects for every module/dependency in our project.

在函数的最后,我们剩下一个名为modules的数组,它将包含项目中每个模块/依赖项的模块对象。

Now that we have that, we can move on to the final step: packing!

现在我们有了这个,我们可以继续进行最后一步:打包!

填料 (Packing)

In the browser, there is no such thing as modules (kind of). But this means that there is no require function, and no module.exports. So even though we have all of our dependencies, we currently have no way to use them as modules.

在浏览器中,没有诸如模块之类的东西。 但这意味着没有require函数,也没有module.exports 。 因此,即使我们拥有所有依赖项,目前也无法将它们用作模块。

模块工厂功能 (Module Factory Function)

Enter the factory function.

输入出厂功能。

A factory function is a function (that’s not a constructor) which returns an object. It is a pattern from object oriented programming, and one of its uses is to do encapsulation and dependency injection.

工厂函数是一个返回对象的函数(不是构造函数)。 它是面向对象编程的一种模式,其用途之一是进行封装和依赖注入。

Sound good?

听起来不错?

Using a factory function, we can both inject our own require function and module.exports object that can be used in our bundled code and give the module its own scope.

使用工厂函数,我们可以注入我们自己的require函数和module.exports对象, module.exports对象可以在我们的捆绑代码中使用,并为模块提供自己的作用域。

填料 (Packing)

The following is the pack function that is used for packing.

以下是用于打包的打包功能。

Most of that is just template literals of JavaScript, so let’s discuss what it’s doing.

其中大多数只是JavaScript的模板文字,因此让我们讨论一下它在做什么。

First up is modulesSource. Here, we are going through each of the modules and transforming them into a string of sources.

首先是modulesSource 。 在这里,我们将遍历每个模块,并将它们转换成一连串的资源。

So what is the output like for a module object?

那么模块对象的输出是什么样的呢?

Now it’s a little hard to read, but you can see that the source is encapsulated. We are providing modules and require using the factory function as I mentioned before.

现在有点难以理解,但是您可以看到源已封装。 我们正在提供modules并且require使用我之前提到的工厂功能。

We are also including the modules map that we constructed during the dependency resolution.

我们还包括在依赖性解析期间构造的模块映射。

Next in the function, we join all of these to create a big object of all the dependencies.

在函数的下一步,我们将所有这些连接起来以创建一个具有所有依赖关系的大对象。

The next string of code is an IIFE, which means that when you run that code in the browser (or anywhere else), the function will run immediately. IIFE is another pattern for encapsulating scope, and is used here so we don’t pollute the global scope with our require and modules.

下一个代码字符串是IIFE,这意味着当您在浏览器(或其他任何地方)中运行该代码时,该函数将立即运行。 IIFE是封装范围的另一种模式,在这里使用IIFE,因此我们不会用我们的require和模块污染全局范围。

You can see that we are defining two require functions, require and localRequire.

您可以看到我们正在定义两个require函数, requirelocalRequire

Require accepts the id of a module object, but of course the source code isn’t written using ids. Instead, we are using the other function localRequire to take any arguments to require by the modules and convert them to the correct id. This is using those module maps.

Require接受模块对象的ID,但是源代码当然不是使用ID编写的。 取而代之的是,我们使用另一个函数localRequire来获取模块要求的任何参数,并将其转换为正确的ID。 这是使用那些模块映射。

After this, we are defining a module object that the module can populate, and passing both functions into the factory, after which we return module.exports.

此后,我们定义了一个module object ,该模块可以填充该module object ,并将这两个函数都传递给工厂,然后返回module.exports

Lastly, we call require(0) to require the module with an id of 0, which is our entry file.

最后,我们调用require(0)要求ID为0的模块,这是我们的入口文件。

And that’s it! Our module bundler is 100% complete!

就是这样! 我们的模块捆绑器已100%完成!

恭喜你! ? (Congratulations! ?)

So we now have a working module bundler.

因此,我们现在有了一个工作正常的模块捆绑器。

This probably shouldn’t be used in production, because it’s missing loads of features (like managing circular dependencies, making sure each file gets only parsed once, es-modules, and so on) but this has hopefully given you a good idea of how module bundlers actually work.

这可能不应该在生产中使用,因为它缺少许多功能(例如管理循环依赖项,确保每个文件仅被解析一次,es-modules等),但这希望可以给您一个很好的想法模块捆绑器实际上可以工作。

In fact, this one works in about 60 lines if you remove all of the source code.

实际上,如果您删除了所有源代码,则此代码行约60行。

Thanks for reading, and I hope you have enjoyed a look into the workings of our simple module bundler. If you did, make sure to clap ? and share.

感谢您的阅读,我希望您喜欢我们的简单模块捆绑器。 如果这样做,请确保拍手? 和分享。

This article was originally posted on my blog.

本文最初发布在我的博客上 。

Check out the source https://github.com/adamisntdead/wbpck-bundler

查看源代码https://github.com/adamisntdead/wbpck-bundler

翻译自: https://www.freecodecamp.org/news/lets-learn-how-module-bundlers-work-and-then-write-one-ourselves-b2e3fe6c88ae/

python模块捆绑器组件

python模块捆绑器组件_让我们学习模块捆绑器如何工作,然后自己编写相关推荐

  1. python图像识别算法 识别数量_使用深度学习(CNN)算法进行图像识别工作时,有哪些data augmentation 的奇技淫巧?...

    估计很多搞深度学习的都遇到过这个情况:有不错的想法,可以用深度学习模型实现.于是兴致勃勃的上网找相关数据集,结果却发现只有很少一部分图像. 你想起来,很多常见的数据集都有成千上万张井然有序的图像,你还 ...

  2. python字节码执行函数_做一个字节码追踪器,从内部理解 Python 的执行过程

    最近我在研究 Python 的执行模型.我对 Python 内部的东西挺好奇,比如:类似 YIELDVALUE 和 YIELDFROM 此类操作码的实现:列表表达式.生成器表达式以及一些有趣的Pyth ...

  3. python后端学什么框架_献给正在学习python的你, 10个最受欢迎的Python开源框架

    很多小伙伴在学习wen的时候说,有没有几个常用的框架,好多小伙伴都只说对了其中几个,只有少部分是说正确的,想要了解更多,欢迎大家订阅微信公众号:Python从程序猿到程序员,或者加4913.08659 ...

  4. python零基础书推荐_零基础学习Python(Python初学者、Python入门)常见问题:资料、社区、书籍推荐...

    Python web开发 QQ学习群:338985564 ,欢迎各位加入,一起学习. 本文针对零基础的,想学习Python者.本文会不定时更新. 一.学会使用搜索引擎,尤其是Google. 推荐阅读文 ...

  5. tableau获取筛选器值_认识Tableau中的筛选器

    Tableau中的筛选器: (1)提取筛选器(2)数据源筛选器(3)上下文筛选器(4)维度筛选器(5)度量筛选器(6)参数筛选器(7)表计算筛选器(8)页面筛选器 对筛选器进行简单的分类: 数据层(提 ...

  6. aspen中再沸器模拟_【单元操作001】再沸器第一波·Aspen Plus中的再沸器设置

    蒸馏操作是通过汽化.冷凝达到提浓的目的,加热汽化主要通过再沸器来完成,相对而言,精馏塔的再沸器种类较多,选择时要考虑的因素也比较多.这一系列的文章,小编试图通过流程模拟.再沸器排布.再沸器类型及在工程 ...

  7. python调用按键精灵插件_谈一谈火车采集器的插件使用

    ​ 火车采集器.火车浏览器这两款软件大家在平常工作中应该经常使用吧,有数据采集需求和各类公司运营人员想必都亲自使用过这个软件吧! 今天小编就与大家分享下两款软件所支持的插件,并讲解下每款插件的功能.一 ...

  8. python安装缺少api怎么办_请问缺少win32api模块该如何解决?

    32位WINDOWS7,PYTHON3.6.2环境下,一个简单的爬虫程序,加载了一些包: from scrapy.selector import Selector from scrapy import ...

  9. python 数组合并排重_并排深度学习:Julia vs Python

    python 数组合并排重 Julia could possibly be the biggest threat to Python. For a variety of applications, J ...

最新文章

  1. 危害企业IT系统最严重的五个安全威胁
  2. 2019南昌网络赛-I(单调栈+线段树)
  3. am335x 配置 GPIO 为可输入也可输出
  4. Mysql 零距离-入门(五)操作数据表
  5. C#.NET编程----Spring.NET NHibernate整合(一)
  6. Python学习笔记——基础篇【第五周】——模块
  7. Ibatis2.0使用说明(二)——配置篇
  8. bootstrap - navbar
  9. C/C++ 编译器优化
  10. Redis无法保存ef复杂对象
  11. 火山编程开发平台pc版|火山软件开发平台下载 附使用教程
  12. HttpUtils调用
  13. 利用R语言编写量化投资策略
  14. 泰坦尼克号生存预测python_用Python预测泰坦尼克号生存情况
  15. 51单片机DHT11温湿度ESP8266WiFi手机APP显示设计
  16. 国内各省市有关中小学少儿编程进展(节选)
  17. C++stl翁恺老师笔记
  18. 解决导出excel表格无法打开的问题
  19. Android Studio + Esp32Cam 实现手机APP实时传输监控视频
  20. 如何快速干净彻底的卸载Oracle11g

热门文章

  1. 直线立体几何——基础
  2. Java项目校园兼职平台(三层架构+设计模式重构版)(含代码)
  3. 鸿蒙系统操作界面布局,华为鸿蒙操作系统大曝光
  4. 泰斗 GPS模块调试(2)
  5. Linux Kernel运行时安全检测之LKRG-原理篇
  6. RFID标签的知识(1)--从频率开始
  7. 分布式数据库中间件——Mycat2
  8. 高等数学(第七版)同济大学 习题5-1 个人解答
  9. 区块链/以太坊/DEX-在以太坊上构建 GraphQL API
  10. Qt_Q_DISABLE_COPY