浅谈JavaScript工具链不完全指南

目录
  • 概述
  • 静态类型检查
  • 代码风格检查(Linter)
  • 包管理器
  • 模块加载器
  • 打包工具
  • 任务管理工具(Task Runner)
  • 转译器
  • 构建工具
  • 调试工具
  • Node 进程管理器
  • 项目脚手架

概述

在 JavaScript 语言日渐强大的同时,与其配套的开发工具也蓬勃发展。现在的 Web 前端项目,早已不是写几个 HTML 页面,加点 CSS 和 JS 就完事了。随便一个实用的项目,可能都需要用到一些框架和第三方库,以及相应的脚手架、依赖包管理、预编译、构建打包、压缩合并等等工具。纯手工完成这些任务,已经几乎不太可能了。

科学技术是第一生产力,而工具就是其中的一个体现。工欲善其事必先利其器,既然工具解放了人力,我们就应该拥抱它们。本文总结了围绕 JavaScript 的一系列工具,看看一个常见的项目到底需要用到哪些工具。

静态类型检查

JavaScript 本身是一门动态脚本语言,是弱类型的。也就是说,没有编译阶段的数据类型检查,只能在运行时确定类型。好处是比较灵活,简单易学,代码量也比较少。缺点也是明显的,就是稍不注意容易出 bug,特别是大型项目,如果没有开发规范,任由开发人员自由发挥,维护起来简直就是灾难。为了弥补这个缺陷,一些自带类型系统、可转译成 JavaScript 的语言出现了。

Flow:Facebook 出品,用 OCaml 写的 JavaScript 静态类型检查系统。支持类型系统、类型标注,可定义 library,提供代码 lint 等。Vue.js 2.x 就是用 Flow 写的。不过,Vue 3.0 改用另一种静态类型语言了,那就是 TypeScript。

TypeScript:TypeScript 是微软开发的语言,是 JavaScript 的超集,能够编译成 JavaScript。现在 TypeScript 越来越流行,获得了大量项目的认可。

代码风格检查(Linter)

由于JavaScript 动态语言的特性,在写法上过于灵活,往往导致多人协作的项目代码风格各异,给维护和扩展带来不少麻烦。另外,部分语言特性容易导致 bug,最佳实践里通常不推荐使用。因此,代码 Lint 工具就派上用场了。它不但可以检查代码书写格式,还可以检查出引用未定义的变量等低级错误。

曾经出现过很多种 Lint 工具,比如 JSLint、JSHint、StandardJS、JSCS 等等,现在有大一统的趋势,基本都用 ESLint 了。

刚开始用 Lint 工具的时候可能会不适应,因为限制太多,动不动就警告和报错。但从长远来看,JavaScript 项目引入 Linter 还是有必要的。

包管理器

JavaScript 之所以能够遍地开花,很大程度是因为技术生态非常繁荣,各种第三方库应有尽有。如此庞大的第三方库集合,势必需要一个管理平台,负责第三方包的托管、版本管理、下载安装和依赖管理等。

npm:JavaScript 包管理器的集大成者,目前最主流的工具。 基于 Node.js,包含网站和 CLI,上面的包总数超过 100万,基本涵盖了 JavaScript 项目所需的方方面面。

yarn:2016 年 Facebook 推出的包管理器,跟 npm registry 兼容,主打 CLI 的快速、安全和确定性。

bower:曾经比较流行,用于管理前端的 JavaScript 包,因为当初 npm 只支持 node 环境的包管理。随着 npm 和 yarn 同时支持 node 和浏览器端的包管理,bower 也逐渐淡出历史了。

pnpm:通过硬链接(hard links)的方式在硬盘上对某个版本的模块只保存一份,可以在多个项目之间共用,从而节省了大量硬盘空间,顺便也加快了模块安装速度。

模块加载器

JavaScript 早期没有语言层面的模块化支持,导致大型项目的依赖管理非常不方便。变量名冲突、全局变量污染、模块加载顺序等问题比较突出。曾经出现过各种模块化方案,比如 CommonJS Modules (CJS),Asynchronous Module Definition (AMD)和 Universal Module Definition (UMD)。从 2015 年开始,ES6 从语言层面支持了模块化,即 ECMAScript Modules (ESM)。

除了上述常见的 JavaScript 模块格式,还有像 System.register或全局模块,以及一些非 JavaScript 模块,比如 JSON modules,CSS modules,Web Assembly 等。

模块加载器就是加载和处理上面各种类型模块代码的工具,有同步和异步、静态和动态之分。通常,一个模块放在一个单独的文件里,通过一些指令来导入。当一个项目有几十上百个模块的时候,如何保证它们的加载执行先后顺序就是个问题。不用担心,模块加载器会帮你处理好依赖关系。

RequireJS:实现了 AMD 模块加载,主要用于浏览器端,也可以在 Node 里使用。

SystemJS:一个动态模块加载器,可以加载所有类型的 JavaScript 模块,甚至包括非 JavaScript 模块,可用于浏览器和 Node。

StealJS:可以加载 ESM,ADM 和 CJS 格式的模块。

ES Module Loader:浏览器实现的模块加载器,Node.js 里加上 --experimental-modules标志也能使用。

以上模块加载器是在运行时加载和执行代码的。不要跟构建工具里的各种 loader 混淆,那些是在构建时进行预处理的工具,只是做一些格式转换。

打包工具

一个实际的生产项目,通常不是把源码直接发布到服务器上。而是通过一些工具对各种模块和静态资源进行整合处理,最终生成的代码可能跟源码完全不一样了。这就是打包工具的作用。比较常见的打包工具有:

Webpack:可以说是最流行的打包器,几乎是大部分项目的标配。它本身只能识别 JavaScript 和 JSON 文件,但是它的架构设计提供了无限的可能,通过各种 loader 可以处理任意类型的资源,通过插件可以优化打包结果和进行资源管理、注入环境变量等。它的构建目标也可以根据平台定制,比如浏览器、Node.js、web worker, Electron 等。

Rollup:也是一个优秀的打包器,支持输出 library 和 application。它最大的卖点就是默认支持 ES 模块,很早就实现了 tree-shaking 功能。同时也具备插件和 hook 功能,可定制化也比较好。

Parcel:工具界的后起之秀,号称“零配置*的打包器,如果你曾经被 Webpack 繁琐的配置困扰过,那它可能会吸引你。

Browserify:应用范围稍窄的打包器,专门用于转换 Node.js 包以便能在浏览器运行。它跟 Node.js 使用相同的模块系统,有些模块只用于 Node 平台,通过它的转换就可以在浏览器端使用了。它只能处理纯 JavaScript 模块,通常跟 Gulp 配合使用。

Metro:React Native 专用的打包器,通过一个入口文件和各种配置,最后打成包含所有代码和依赖的单个 JavaScript 文件。

任务管理工具(Task Runner)

Task Runner 的作用是自动化执行项目所需的各种重复性动作,比如:

  • CSS 预处理 (Less, Sass)
  • CSS 自动添加新特性属性前缀(Autoprefixer)
  • 优化图片
  • 合并、压缩 JavaScript 文件
  • 监听文件变化,自动执行任务

比较主流的任务管理器是 Grunt 和 Gulp,Webpack 也算一个。

Grunt:命令行工具,通过精细化的配置和丰富的插件可以完成很多复杂的任务。

Gulp:跟 Grunt 不同,Gulp 采用流式管道组合多个任务,任务之间的临时结果是放在内存中的,执行效率会高很多。

Webpack:又是你,Webpack。任务管理只是 Webpack 强大功能的一部分,通过不同的插件在构建的不同阶段执行个性化的任务。

如果你觉得上面几个任务管理器有点杀鸡用牛刀,你也可以根据实际情况选用 bash 脚本,npm 脚本或者 Makefile 等实现一些简单的任务管理。

转译器

JavaScript 转译器的作用是将非 JavaScript 语言(TypeScript,CoffeeScript,LiveScript 等)或不同版本的 JavaScript(ES6,ES7,ES8 等)翻译成符合目标平台要求(兼容性、变量混淆、严格模式等)的等价代码。

大部分转译器在处理源码和代码优化的过程中都使用抽象语法树(AST)作为中间格式。AST 将源码逐步拆分解析成带有元数据的树形结构:

Code --(parse)-->AST--(transform)-->AST--(generate)-->Code

Babel是目前主流的 JavaScript 转译器,它的工具链体系主要用于将 ES6 以上版本的 JavaScript 转译成向后兼容浏览器的代码。Babel 可以转换语法、提供目标平台缺失的特性支持、转换源码等。

有了 Babel,我们可以尽早用上新的语言特性,而不用担心目标浏览器是否支持。

构建工具

构建其实是个综合概念,它包含了模块打包、源码转译、任务管理等多个步骤。其他语言和平台有各种 Build 工具,比如 Make,Gradle,Ant,Maven,Rake 或 MSBuild 等。其中 Make 是最常见的通用构建工具,通常用于 C 语言,但其实也可以用于构建 JavaScript 项目。

对于 JavaScript 工具链来说,构建的目标可能是 npm 包、网站、Node 服务器、RN 应用、Electron 应用等等。有些任务可用专门的工具完成,但构建是个复杂的过程,通常需要综合使用多个工具。

比如 Build 可以用 Buck,Bazel,Lerna 等工具同时管理多个模块,实现增量 Build(只重新构建有改动的模块,提高效率)。任务管理使用 Grunt 和 Gulp,模块打包用 Webpack、Rollup、Parcel、Browserify 等。

调试工具

调试器在开发过程中必不可少,它可以在 Node.js 和浏览器中跟踪查看运行中的代码。通常会提供断点、单步执行、监视变量、查看内存和 CPU 使用情况等功能。

Chrome DevTools:Chrome 浏览器自带的开发者工具,是目前浏览器开发工具里最好用的(没有之一)。它的功能之强大,用法之多可以写本书了。

node-inspector:早期用于调试 Node.js 代码的工具,现在基本不用了,因为 Node.js 已经内置了基于 DevTools 的调试器。

VS Code:又一调试神器,内置 Node.js 调试器,还能调试 TypeScript 和其他能转译成 JavaScript 的语言。

Node 进程管理器

Node 进程管理器用于管理运行中的 Node 应用程序。提供高可用、自动重启、文件监控、性能和资源监控和集群等功能。

Forever:顾名思义,它的作用是保持 Node.js 程序永远运行。它是一个简单的命令行工具,对小型 Node.js 应用比较方便。

PM2:用于生产环境的 Node.js 进程管理工具,内置负载均衡、自动重启和日志、监控和集群管理等功能。

StrongLoop Process Manager(Strong-PM):跟 PM2 差不多,也可用于生产环境的 Node.js 进程管理,有多主机部署功能。

另外,SystemD 是 Linux 系统里的默认进程管理器,可用它把 Node.js 应用作为服务运行。

项目脚手架

随着项目复杂度的提升,创建新项目的步骤也变得越来越繁琐,可能需要重复大量的配置工作。这个时候就需要项目脚手架了。很多框架都提供了脚手架工具,比如 Vue.js 有 Vue CLI,Angular 有 Angular CLI,React 有 create-react-app 等。也有通用的脚手架,Yeoman 就是最流行的一个。

  • 快速创建新项目
  • 创建模块或 package
  • 启动新服务
  • 统一代码风格、最佳实践等
  • 项目推广,让用户快速上手示例 app

以上就是浅谈JavaScript工具链不完全指南的详细内容,更多关于JS工具链不完全指南的资料请关注我们其它相关文章!

(0)

相关推荐

  • 分享一款超好用的JavaScript 打包压缩工具

    背景 平时大家在开发 Js 项目的时候,可能已经离不开 webpack 等打包工具了.而 webpack 打包速度大概就是"能用"的水平.大概去年开始,我就开始在构想,如果能写一个极速的打包工具,功能未必需要很强,可能对小项目非常有用.去年我用 C++ 写完 parser 之后,便没什么动力写下去了.但是最近发现有这个想法的不止我一个,Figma 的 CTO 业余之际写了一个打包器 https://github.com/evanw/esbuild ,可以说完完全全实现了我想象中的需求,

  • JavaScript 实现自己的安卓手机自动化工具脚本(推荐)

    一个神奇的 APP 这个软件叫做 Auto.js,只支持安卓,是一个不需要 Root 权限的 JavaScript 自动化软件.什么意思呢,就是在你的安卓手机上安装这个 APP,然后通过编写 JS 脚本的方式实现自动化操作.类似的也有其他的一些软件,比如苹果自带的快捷操作,可以通过自定义配置完成一系列的流程,但是由于其目标是所有人都可以使用,所以定制的时候就没有那么灵活. 而 Auto.js 通过写代码的方式定制,那不用多说,灵活性肯定是没的说,关键的是,竟然写 JS 就可以,不用懂 Java,

  • JavaScript常用工具函数汇总(浏览器环境)

    前端业务中比较常用的JavaScript工具函数,浏览器环境常用,可直接拷贝在项目里使用.这里统一整理,方便查阅,本文章会持续更新. 一.file转为base64 /** * file转为base64 * @param {*} file file对象 * @param {*} callback */ export const fileToDataURL = (file, callback) => { let freader = new FileReader(); freader.readAsDa

  • JavaScript常用工具函数大全

    本文实例总结了JavaScript常用工具函数.分享给大家供大家参考,具体如下: 为元素添加on方法 Element.prototype.on = Element.prototype.addEventListener; NodeList.prototype.on = function (event, fn) {. []['forEach'].call(this, function (el) { el.on(event, fn); }); return this; }; 为元素添加trigger方

  • JavaScript检测是否开启了控制台(F12调试工具)

    js检测用户是否打开调试工具(chrome) (function(){ var re=/x/; var i=0; console.log(re); re.toString=function(){ window.close(); return '第'+(++i)+'次打开控制台'; } })(); JavaScript检测是否开启了控制台(调试工具) 测试后在chrome有效 不少人防止别人趴源码,一般采用检测按键F12之类的,但是这些基本没什么用 现在介绍一个方法,非常管用,可以检测到你是否开启

  • JS检测浏览器开发者工具是否打开的方法详解

    在某些情况下我们需要检测当前用户是否打开了浏览器开发者工具,比如前端爬虫检测,如果检测到用户打开了控制台就认为是潜在的爬虫用户,再通过其它策略对其进行处理.本篇文章主要讲述几种前端JS检测开发者工具是否打开的方法.  一.重写toString() 对于一些浏览器,比如Chrome.FireFox,如果控制台输出的是对象,则保留对象的引用,每次打开开发者工具的时候都会重新调用一下对象的toString()方法将返回结果打印到控制台(console tab)上. 所以只需要创建一个对象,重写它的to

  • node.js中npm包管理工具用法分析

    本文实例讲述了node.js中npm包管理工具用法.分享给大家供大家参考,具体如下: 现在安装node.js,默认就会帮我们装上了npm包管理工具,npm主要用来下载,安装,管理第三方模块. 创建一个包描述文件: npm init [-y] 查看包的信息 npm info <package-name> 查看包的版本信息 npm info <package-name> versions 安装指定的包: npm install <package-name> 默认会安装在当前

  • JavaScript代码压缩工具UglifyJS和Google Closure Compiler的基本用法

    一.UglifyJS UglifyJS是用JavaScript编写的JavaScript压缩工具. 官网:http://lisperator.net/uglifyjs/ 1.通过NPM安装UglifyJS (1)安装Node.js 从Node.js官网https://nodejs.org/en/下载对应平台的安装程序,当前最新版本11.4.0,推荐版本10.14.2. 本人下载的是10.14.2,下载下来是一个node-v10.14.2-x64.msi安装包,按照默认下一步安装. 安装成功后在c

  • JavaScript常用工具函数库汇总

    对象或数组的深拷贝 /** * 对象或数组的深拷贝 * @param {*} cloneObj 被克隆的对象 * @param {*} targetObj 克隆的目标对象 * @param {*} isOverride 若属性重复,是否覆盖被克隆对象的属性 */ function deepClone(cloneObj, targetObj, isOverride = true) { const _toString = Object.prototype.toString if (_toString

  • 浅谈JavaScript工具链不完全指南

    目录 概述 静态类型检查 代码风格检查(Linter) 包管理器 模块加载器 打包工具 任务管理工具(Task Runner) 转译器 构建工具 调试工具 Node 进程管理器 项目脚手架 概述 在 JavaScript 语言日渐强大的同时,与其配套的开发工具也蓬勃发展.现在的 Web 前端项目,早已不是写几个 HTML 页面,加点 CSS 和 JS 就完事了.随便一个实用的项目,可能都需要用到一些框架和第三方库,以及相应的脚手架.依赖包管理.预编译.构建打包.压缩合并等等工具.纯手工完成这些任

  • 浅谈javascript原型链与继承

    js原型链与继承是js中的重点,所以我们通过以下三个例子来进行详细的讲解. 首先定义一个对象obj,该对象的原型为obj._proto_,我们可以用ES5中的getPrototypeOf这一方法来查询obj的原型,我们通过判断obj的原型是否与Object.prototype相等来证明是否存在obj的原型,答案返回true,所以存在.然后我们定义一个函数foo(),任何一个函数都有它的prototype对象,即函数的原型,我们可以在函数的原型上添加任意属性,之后通过new一个实例化的对象可以共享

  • 浅谈JavaScript的内置对象和浏览器对象

    在javascript中对象通常包括两种类型:内置对象和浏览器对象,此外,用户还可以自定义对象. 对象包含两个要素: 1. 用来描述对象特性的一组数据,也就是若干变量,通常称为属性. 2. 用来操作对象特性的若干动作,也就是若干函数,通常称为方法. 浏览器对象 对象 含义 anchor 当前文档中设置了name属性的超链接 applet 当前文档中的小程序 area 客户端图形映射中的区域 button 表单中的按钮 checkbook 表单中的复选框 document 当前窗口中的HTML文档

  • 浅谈JavaScript 执行环境、作用域及垃圾回收

    执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境都有一个与之关联的变量对象. 全局执行环境是最外围的一个执行环境.根据JavaScript实现所在的宿主环境不同,表示执行环境的对象也不一样.在Web浏览器中,全局执行环境被认为是window对象.因此,所有的全局变量和函数都是作为window对象的属性和方法创建的. 变量对象:环境中定义的所有变量和函数都保存在这个对象中. 作用域链:当代码在一个环境中执行时,会创建变量对象的一个作用域链.作用域链的用途是保证对执行环

  • 浅谈JavaScript 覆盖原型以及更改原型

    覆盖原型 //囚犯示例 //1.定义原型对象 var proto = { sentence : 4, //监禁年限 probation: 2 //缓刑年限 }; //2.定义原型对象的构造函数 var Prisoner = function(name, id) { this.name = name; this.id = id; }; //3.将构造函数关联到原型 Prisoner.prototype = proto; //4.实例化对象--采用工厂函数实例化对象 var makePrisoner

  • 浅谈JavaScript对象的创建方式

    通过Object构造函数或对象字面量创建对象时,使用同一个接口创建很多对象时,会产生大量的重复代码.为了简化,引入了工厂模式. 工厂模式 function createPerson(name, age, job) { var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; obj.sayHello(){ alert(this.name); }; return obj; } var p1 = createPers

  • 浅谈JavaScript中的属性:如何遍历属性

    在JavaScript中,遍历一个对象的属性往往没有在其他语言中遍历一个哈希(有些语言称为字典)的键那么简单.这主要有两个方面的原因:一个是,JavaScript中的对象通常都处在某个原型链中,它会从一个或多个的上层原型上继承一些属性.第二个原因是,JavaScript中的属性不光有值,它还有一些除了值以外的其他特性,其中一个影响属性遍历的特性就是[[Enumerable]],如果该值为true,则称这个属性是可枚举的,否则反之. 知道了这些,我们就可以把属性的遍历分为四种情况. 注:示例代码中

  • 浅谈JavaScript对象与继承

    JavaScript是我在C语言之后接触的第二门编程语言,大一暑假的时候在图书馆找了一本中国人写的JavaScript程序设计来看.那个时候在编程方面几乎还是小白,再加上那本书根本没有提JavaScript的编程机制,又有一些误导性的话,一直以来对JavaScript有很深的误解,认为JavaScript只是一门在浏览器上运行的面向对象语言,值此文来写下JavaScript当中很具有迷惑性和容易误解的地方.当然限于作者水平有限,也没有什么开发经验,所以难免有疏漏之处,还望批评指正. JavaSc

  • 浅谈JavaScript中this的指向问题

    JavaScript中this指向问题 记得初学 JavaScript 时,其中 this 的指向问题曾让我头疼不已,我还曾私自将其与闭包.原型(原型链)并称 JS 武林中的三大魔头.如果你要想在 JS 武林中称霸一方,必须将这三大魔头击倒.个人认为在这三大魔头中,this 指向问题的武功最菜(难度最低).俗话说柿子捡软的捏,那我们就先从 this 指向问题下手. 先记住攻克 this 指向问题的口诀(前辈们的总结):哪个对象调用函数,函数里的 this 就默认指向哪个对象(注意 this 只能

  • 浅谈JavaScript 浏览器对象

    window window对象不但充当全局作用域,而且表示浏览器窗口. window对象有innerWidth和innerHeight属性,可以获取浏览器窗口的内部宽度和高度.内部宽高是指除去菜单栏.工具栏.边框等占位元素后,用于显示网页的净宽高.还有一个outerWidth和outerHeight属性,可以获取浏览器窗口的整个宽高. 补充: 网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:

随机推荐