当我们使用模块化的时候,每个文件都代表一个模块,当我们在一个模块里面使用另外一个模块的时候,我们一般会require其他模块,require得到的内容就是被require文件中exports暴漏出去的那部分内容。通过了require和exports实现了模块化,这样就会对一个很大的项目进行模块化的分解,这样的好处就是会使源码更加的清晰,当我们需要修改的时候找到对应的文件及对应的模块进行修改即可。否则的话,我们面对的就是一个很长很长的js,那样修改起来就会很麻烦。一般情况下,模块化只能在node.js去运行模块化的项目,因为node环境中具有CommonJS 规范也就是require和exports这一套。其他的打包工具也是根据node.js这个原理去执行的。换句话说,用模块化写的代码可以node环境下正常执行,但是在浏览器中就不能正常执行,因为浏览器并不会识别require和exports这个东西。因此我们想在浏览器里面使用模块化,就要对源码进行处理,使用一个工具对我们的源码(模块化)进行加工,放在一起生成一个新文件。然后引入到浏览器中,浏览器会识别这个文件,以后我们改动代码只需要改动源码然后重新生成一个新文件即可。那么我们就要写出一个可以对这些模块化文件进行加工的工具。
family-name.js action.js index.js name.js上面的这四个模块化文件中的require和exports我们并不知道是哪里来的,因此我们可以把它们写成下面的这种形式,那么这个require就是外面的函数调用的时候传递进来的,如果去执行action.js 这个文件就是对exports进行赋值,那么就会把这个结果传递出去。
我们接着在考虑,当我们把这四个模块化文件合并在一个js文件中,就要给它们命名上不同的id,(不加名字的原因:当模块很多的时候,我们的名字就会很麻烦),不如将它们放入到一个对象上,因此有了下面的代码。
0,1,2,3...是它们的id;后面的function是它们对应的函数,那么这个moudles就把我们所有的模块全部拿过来了
现在我们就需要一个工具将我们的源码变成上面文件的代码,目前有两个问题就需要解决:
1.如何将源码变成上面的代码;
2.require里面到底怎么去写(如果里面没有写,那么就只能执行到第一步也就是id=0的时候就卡住了)。
接下来我们就要完善这个require
这里我们把上面的每个模块代码分为两个部分;然后将对应id数的模块代码也分为两个部分:fn和mapping,fn是该模块代码对应的函数,mapping是该模块代码对应的id。当执行 function require(path)时,我们把path当参数传入,mapping[path]就会得到对应的id数,我们就会执行对应的exec(mapping[path])。
然后就是如何将源码变成moudles里面的代码
我们要将源码变成moudles里面的代码:
首先要写一个类似于node.js(用node.js去写)的工具,读取其入口文件,也就是index.js这个文件。我们require('fs'),然后同步解读这个文件,然后读取./src/index.js这个文件,读完之后获取里面的内容;
然后要解析其依赖 getDependencies(str),把我们入口文件里面的内容传入进去就会得到依赖。注:(这里使用了正则表达式,如果我们为了更加的稳妥,可以使用其他的工具(Babylon),它的作用就是把当前的文件解析成ast(抽象语法树))
这里我们通过控制台可以看到,这个while循环里面,如果resuit≠null那么它就会执行,然后它的第零项时匹配的结果,第一项就会得到对应的依赖,将得到的依赖push到dependencies里面,然后接着循环,直到它输出为null
有了这个依赖以后,把这个模块变成一个对象,我们认为模块会有一些属性,例如:id,filename,dependencies,code。因此我们写一个creatAsset(filename),给我传一个文件名,把这个文件内容读取出来,同时再给每个模块创建的过程中赋值一个id,起初这个id=0,随后每一个+1,dependencies就是获取文件内容里面的依赖,code就是给每个文件内容加上一个包裹function(require,exports,moudle){},就代表了当前code这个字符串。
接下来我们就要得到类似下面的模块
通过上面的方法我们就得到了自己想要得到的单一模块的类型,然后我们想要把这些拼接成下面的类型
通过最后一步我们把前面所有得到的东西拼接在一块就是我们想要的东西。
最后附上完整的代码:
网友评论