Grunt、Gulp 是基于任务运行的工具: 它们会自动执行指定的任务, 就像流水线,把资源放上去然后通过不同插件进行加工,它们包含活 跃的社区,丰富的插件,能方便的打造各种工作流。
Webpack是基于模块化打包的工具: 自动化处理模块,webpack把一 切当成模块,当 webpack 处理应用程序时,它会递归地构建一个依 赖关系图 (dependency graph),其中包含应用程序需要的每个模块, 然后将所有这些模块打包成一个或多个 bundle。
因此这是完全不同的两类工具,而现在主流的方式是用npm script 代 替 Grunt、Gulp,npm script 同样可以打造任务流。
webpack 适用于大型复杂的前端站点构建: webpack 有强大的 loader 和插件生态,打包后的文件实际上就是一个立即执行函数,这个立即 执行函数接收一个参数,这个参数是模块对象,键为各个模块的路径, 值为模块内容。立即执行函数内部则处理模块之间的引用,执行模块 等,这种情况更适合文件依赖复杂的应用开发。
rollup 适用于基础库的打包,如 vue、d3 等: Rollup 就是将各个模 块打包进一个文件中,并且通过 Tree-shaking 来删除无用的代码, 可以最大程度上降低代码体积,但是 rollup 没有 webpack 如此多的的 如代码分割、按需加载等高级功能,其更聚焦于库的打包,因此更适 合库的开发。parcel 适用于简单的实验性项目: 他可以满足低⻔槛的快速看到效 果,但是生态差、报错信息不够全面都是他的硬伤,除了一些玩具项 目或者实验项目不建议使用。
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL
去引用输出的文件
url-loader:和 file-loader 类似,但是能在文件很小的情况下以
base64 的方式把文件内容注入到代码中去 source-map-loader:加载额外的 Source Map 文件,以方便断点调试
image-loader:加载并且压缩图片文件
babel-loader:把 ES6 转换成 ES5
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作 去加载 CSS。
eslint-loader:通过 ESLint 检查 JavaScript 代码
注意:在 Webpack 中,loader 的执行顺序是从右向左执行的。因为 webpack 选择了 compose 这样的函数式编程方式,这种方式的表达式 执行是从右向左的。
define-plugin:定义环境变量
html-webpack-plugin:简化 html文件创建
uglifyjs-webpack-plugin:通过 UglifyES 压缩 ES6 代码
webpack-parallel-uglify-plugin: 多核压缩,提高压缩速度
webpack-bundle-analyzer: 可视化 webpack 输出文件的体积
mini-css-extract-plugin: CSS 提取到单独的文件中,支持按需加 载
bundle:是由 webpack 打包出来的文件;
chunk:代码块,一个 chunk 由多个模块组合而成,用于代码的合并和分割;
module:是开发中的单个模块,在 webpack 的世界,一切皆模块,一 个模块对应一个文件,webpack 会从配置的 entry 中递归开始找出所 有依赖的模块。
不同的作用:
Loader 直译为"加载器"。Webpack 将一切文件视为模块,但是 webpack 原生是只能解析 js文件,如果想将其他文件也打包的话,就会用到 loader 。 所以 Loader 的作用是让 webpack 拥有了加载和解析非 JavaScript文件的能力。
Plugin 直译为"插件"。Plugin 可以扩展 webpack 的功能,让 webpack 具有更多的灵活性。在 Webpack 运行的生命周期中会广播出许多事 件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
不同的用法:
Loader 在 module.rules 中配置,也就是说他作为模块的解析规则 而存在。 类型为数组,每一项都是一个 Object ,里面描述了对于 什么类型的文件( test ),使用什么加载( loader )和使用的参数 ( options )
Plugin在 plugins 中单独配置。类型为数组,每一项是一个 plugin 的实例,参数都通过构造函数传入
webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧 的模块。
原理:
首先要知道 server 端和 client 端都做了处理工作:
第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生
修改,webpack 监听到文件变化,根据配置文 件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript
对象保存在内存中。
第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在 这一步,主要是 dev-server 的中间件 webpack- dev-middleware 和 webpack 之间的交互,webpack-dev-middleware 调用 webpack 暴露的 API 对代码变化进行监 控,并且告诉 webpack,将代码打包 到内存中。
第三步是 webpack-dev-server 对文件变化的一个监控,这一步不同 于第一步,并不是监控代码变化重新打包。当我们在配置文件中配置 了 devServer.watchContentBase 为 true 的时候,Server 会监听 这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进 行 live reload。注意,这儿是浏览器刷新,和 HMR 是两个概念
第四步也是 webpack-dev-server 代码的工作,该步骤主要是通过 sockjs(webpack-dev-server 的依赖)在浏览器端和服务端之间建 立一个 websocket ⻓连接,将 webpack 编译打包的各个阶段的状态 信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化 的信息。浏览器端根据这些 socket 消息进行不同的操作。当然服务 端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
webpack-dev-server/client 端并不能够请求更新的代码,也不会执 行热更模块操作,而把这些工作又交回给了 webpack
webpack/hot/dev-server 的 工 作 就 是 根 据 webpack-dev-server/client 传给它的信息以及 dev-server 的配 置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是刷新浏 览器,也就没有后面那些步骤了。
HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上 一步传递给他的新模块的 hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端 返回一个 json,该 json 包含了所有要更新的模块的 hash 值,获 取到更新列表后,该模块再次通过 jsonp 请求,获取到最新的模块 代码。这就是上图中 7、8、9 步骤。
而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中, HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在 决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模 块间的依赖引用。
最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行 浏览器刷新来获取最新打包代码。
babel 的转译过程也分为三个阶段,这三步具体是:
解析 Parse: 将代码解析生成抽象语法树(AST),即词法分析与语 法分析的过程;
转换 Transform: 对于 AST 进行变换一系列的操作,babel 接受得 到 AST 并通过 babel-traverse 对其进行遍历,在此过程中进行添 加、更新及移除等操作;
生成 Generate: 将变换后的 AST 再转换为 JS 代码, 使用到的模 块是 babel-generator。
git 和 svn 最大的区别在于 git 是分布式的,而 svn 是集中式的。 因此我们不能再离线的情况下使用 svn。如果服务器出现问题,就没 有办法使用 svn 来提交代码。
svn 中的分支是整个版本库的复制的一份完整目录,而 git 的分支 是指针指向某次提交,因此 git 的分支创建更加开销更小并且分支 上的变化不会影响到其他人。svn 的分支变化会影响到所有的人。
svn 的指令相对于 git 来说要简单一些,比 git 更容易上手。
GIT 把内容按元数据方式存储,而 SVN 是按文件:因为 git 目录是处 于个人机器上的一个克隆版的版本库,它拥有中心版本库上所有的东 西,例如标签,分支,版本记录等。
GIT 分支和 SVN 的分支不同:svn 会发生分支遗漏的情况,而 git 可 以同一个工作目录下快速的在几个分支间切换,很容易发现未被合并 的分支,简单而快捷的合并这些文件。
GIT 没有一个全局的版本号,而 SVN 有GIT 的内容完整性要优于 SVN:GIT 的内容存储使用的是 SHA-1 哈希 算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题 时降低对版本库的破坏
git fetch 只是将远程仓库的变化下载下来,并没有和本地分支合并。
git pull 会将远程仓库的变化下载下来,并和当前分支合并。
git merge 和 git rebase 都是用于分支合并,关键在 commit 记录 的处理上不同:
git merge 会新建一个新的 commit 对象,然后两个分支以前的 commit 记录都指向这个新 commit 记录。这种方法会保留之前每个 分支的 commit 历史。
git rebase 会先找到两个分支的第一个共同的 commit 祖先记录, 然后将提取当前分支这之后的所有 commit 记录,然后将这个 commit 记录添加到目标分支的最新提交后面。经过这个合并后,两 个分支合并后的 commit 记录就变为了线性的记录了。