本文目录
1.es6 的模块管理 与 commonjs 的对比
2. 简单介绍下前端模块化规范: amd,cmd,commonjs 和 es6 的 module
3.commonjs 和 es6 的 module 哪个支持异步
4.Base64 的原理? 编码后比编码前是大了还是小了
5.webpack 构建原理与运行的基本流程
6.loader 的原理及手些 loader 的思路
7.loader 和 plugin 的区别
8.babel 是什么
9.babel 的工作流程
1.es6 的模块管理 与 commonjs 的对比
CommonJS 输出是值的拷贝, 即原来模块中的值改变不会影响已经加载的该值, ES6 静态分析, 动态引用, 输出的是值的引用, 值改变, 引用也改变, 即原来模块中的值改变则该加载的值也改变.
CommonJS 模块是运行时加载, ES6 模块是编译时输出接口.
CommonJS 加载的是整个模块, 即将所有的接口全部加载进来, ES6 可以单独加载其中的某个接口 (方法),
CommonJS this 指向当前模块, ES6 this 指向 undefined
2. 简单介绍下前端模块化规范: amd,cmd,commonjs 和 es6 的 module
AMD
AMD 是 RequireJS 在推广过程中对模块定义的规范化产出.
AMD 规范则是非同步加载模块, 允许指定回调函数.
AMD 标准中, 定义了下面两个 API:
- require([module], callback)
- define(id, [depends], callback)
即通过 define 来定义一个模块, 然后使用 require 来加载一个模块. 并且, require 还支持 CommonJS 的模块导出方式.
CMD
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出.
CMD 是同步模块定义.
二者的区别是前者是对于依赖的模块提前执行, 而后者是延迟执行. 前者推崇依赖前置, 而后者推崇依赖就近, 即只在需要用到某个模块的时候再 require.
CommonJS
Node.JS 中使用的是这个规范. CommonJS 的核心思想就是通过 require 方法来同步加载所要依赖的其他模块, 然后通过 exports 或者 module.exports 来导出需要暴露的接口.
ESM
在 ES6 中, 我们可以使用 import 关键字引入模块, 通过 exprot 关键字导出模块, 功能较之于前几个方案更为强大, 也是我们所推崇的, 但是由于 ES6 目前无法在浏览器中执行, 所以, 我们只能通过 babel 将不被支持的 import 编译为当前受到广泛支持的 require.
3.commonjs 和 es6 的 module 哪个支持异步
紧接着问了这个问题, emmm.. 当时差点没缓过来, 冷静分析了一波, 然后想到我们最近的项目中在做 react 组件的异步加载, 想到了 es10 版本添加了异步 import() 方式去载入一个模块, 所以答案毫无疑问是 esm 目前支持异步, 其实返回来想想, 如果用排除法这个也很简单, 因为 commonjs 规范主要是给 node 层用的, node 层对于 module 的加载无非就是文件的读写, 所以它根本没有必要去支持异步加载, 读写 io 本身就很快~
4.Base64 的原理? 编码后比编码前是大了还是小了
Base64 是一种基于用 64 个可打印字符来表示二进制数据的表示方法. 编码后的数据比原始数据略长, 为原来的 4/3.
5.webpack 构建原理与运行的基本流程
Webpack 构建运行在 node.JS 环境下, 它的配置文件遵循 CommonJS 规范, webpack.config.JS 导出一个 Object 对象 (或者导出一个 Function, 或者导出一个 Promise 函数, 还可以导出一个数组包含多份配置).Webpack 从入口文件开始, 识别出源码中的模块化导入语句, 递归地找出所有依赖, 然后把入口文件和所有依赖打包到一个单独的文件中 (即一个 chunk), 这就是所谓的模块打包. 最新版的 Webpack, 已经支持了 E6/CommonJS/AMD 等模块化语句.
webpack 运行的基本流程分为初始化, 编译, 输出三个阶段.
初始化:
从配置文件和 shell 文件读取, 合并参数;
加载 plugin
实例化 compiler
编译:
从 entry 发出, 针对每个 module 串行调用对应 loader 翻译文件内容
找到 module 依赖的 module, 递归进行编译处理
输出:
把编译后 module 组合成 chunk
把 chunk 转换成文件, 输出到文件系统
构建流程的详细过程:
初始化: 从配置文件或是 shell 读取与合并参数, 得到最终参数, 实例化插件 new Plugin()
开始编译: 通过上一步初始化得到的最终参数, 初始化一个 Compiler 对象, 加载插件 (依次调用插件中的 apply 方法), 通过执行 Compiler.run 开始编译
确定入口: 根据配置中 entry 找出所有入口文件
编译模块: 从 entry 出发, 调用配置的 loader, 对模块进行转换, 同时找出模块依赖的模块 (如何找? 见下文), 依次递归, 直到所有依赖模块完成本步骤处理
完成模块编译: 这一步已经使用 loader 对所有模块进行了转换, 得到了转换后的新内容以及依赖关系
输出资源: 根据入口与模块之间的依赖关系, 组装成一个个 chunk 代码块, 并且生成文件输出列表
输出成功: 根据配置中的输出路径和文件名, 将文件写入文件系统, 完成构建
6.loader 的原理及手些 loader 的思路
loader 是 webpack 用于在编译过程中解析各类文件格式, 并输出;
loader 本质上就是一个 node 模块, 通过写一个函数来完成自动化的过程;
由此我们就可以在开发模式下, 通过解析各类前端无法解析的文件格式, 然后将其解析后返回为对象或字符串供前端开发时使用, 在 webpack 的编译过程中自动会将我们前端项目中引用的文件格式对应到指定 loader 解析后输出.
比如下面这段 webpack.config.JS 配置
- module.exports = {
- //...
- module: {
- rules: [
- {webpack.config.JS
- test: /\.txt$/,
- use: {
- loader: path.resolve(__dirname, './txt-loader.js'),
- options: {
- name: 'YOLO'
- }
- }
- }
- ]
- }
- }
这是一个非常简单的 loader 来解析 txt 文件, 它将满足以下功能
读取 txt 文件内容并输出为一个对象, 对象内包括文件内容与文件名
读取 webpack loader 选项, 将内容中的 [name] 替换为我们选项 name 的值
loader 能把源文件翻译成新的结果, 一个文件可以链式经过多个 loader 编译. 以处理 SCSS 文件为例:
Sass-loader 把 SCSS 转成 CSS
CSS-loader 找出 CSS 中的依赖, 压缩资源
style-loader 把 CSS 转换成脚本加载的 JavaScript 代码
7.loader 和 plugin 的区别
对于 loader, 它是一个转换器, 将 A 文件进行编译形成 B 文件, 这里操作的是文件, 比如将 A.SCSS 转换为 A.CSS, 单纯的文件转换过程.
plugin 是一个扩展器, 它丰富了 webpack 本身, 针对是 loader 结束后, webpack 打包的整个过程, 它并不直接操作文件, 而是基于事件机制工作, 会监听 webpack 打包过程中的某些节点, 执行广泛的任务
8.babel 是什么
Babel 是一个 JavaScript 编译器
Babel 是一个工具链, 主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法, 以便能够运行在当前和旧版本的浏览器或其他环境中.
9.babel 的工作流程
Babel 的编译过程和大多数其他语言的编译器相似, 可以分为三个阶段:
解析 (Parsing): 将代码字符串解析成抽象语法树.
转换 (Transformation): 对抽象语法树进行转换操作.
生成 (Code Generation): 根据变换后的抽象语法树再生成代码字符串.
来源: http://www.jianshu.com/p/b428e2c9864b