有码友是这么说的:前端工程化是一个很大的话题,甚至到现在都没有一个准确的定义。笔者对前端工程化的理解是:一切能提升前端开发效率,提高前端应用质量的手段和工具都是前端工程化。
一、为什么要工程化?
以下来自这里《透视前端工程化》。
1、极大提升开发效率,是功能实现语法变得简单。
为了减少请求数,前端开发者通常会把大量尺寸较小、细碎的小图片合并成一张大的透明的雪碧图,在 CSS 中通过设置元素的 background-position 来使用图片。如果是完全手动去拼图、测距,将耗费大量的时间。但在雪碧图插件 webpack-spriteSmith 的帮助下,小图可以自动拼成雪碧图,并生成对应的 CSS 样式,插件能帮助我们处理这种毫无技术含量的体力活,效率加倍。
再举一个例子,没有前端脚手架的情况下,如果从零开发一个项目,需要花费大量的时间去初始化项目,比如安装各种 npm 包、配置各种 Webpack 的 loader、配置热加载。如果碰到环境搭建不顺利的情况,还需要花费很长时间去排查问题,单单一个项目初始化的动作就足以耗费一两天的时间。有脚手架工具的情况下,只需要简单的一个初始化命令,2 分钟的时间就可以完成项目的初始化。前端只需要聚焦到业务开发本身,效率大幅提升。
2、降低大型项目的开发难度
首先前端工程化中提倡模块化、组件化。模块化的思想将大型项目的功能进行分解,分拆成一个个独立的模块。每个模块的开发难度直线下降。同时基于版本控制工具 Git,多个开发者可以并行开发,提升开发效率。项目在后期迭代的时候,由于每个模块相对独立,耦合性极低,一个功能的调整往往只需要修改其中的一个模块就可以,风险可控。不至于出现改动一处代码,引发全局问题的情况。
其次,前端工程化提倡用完善的流程规范和代码规范来保证大型应用的质量和可维护性。比如通过 ESlint、stylelint 对代码进行自动校验,通过评审、详细设计、开发、联调、测试、上线等每个环节的控制,确保项目的高质量和按时交付。向主分支合并代码必须经过 code review。流程规范确保了大型项目质量和可维护性的同时能够如期交付。
二、相关概念
正如上面所说,前端工程化是个大话题。那就先来看一些工程化当中涉及的一些基本概念。
1、npm
npm 是 JavaScript 世界的包管理工具,并且是 Node.js 平台的默认包管理工具(用来安装各种 Node.js 的扩展)。通过 npm 可以安装、共享、分发代码,管理项目依赖关系。 npm包管理器,是集成在node中的,所以安装了node也就有了npm。
小马认为类似php的composer,go的modules,linux的yum。
2、less
Less 到底为 CSS 添加了什么功能?
无需多说,看代码一目了然:
@width: 10px;
@height: @width + 10px;
#header {
width: @width;
height: @height;
}
编译输出为:
#header {
width: 10px;
height: 20px;
}
不想深究的看到这就行了。
Less 是 一种动态样式语言。less教程点这里。
Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。
Less 可以运行在 Node 或浏览器端。
在 Node.js 环境中使用 Less :
npm install -g less
> lessc styles.less styles.css
在浏览器环境中使用 Less :
例子:
@base: #f938ab;
.box-shadow(@style, @c) when (iscolor(@c)) {
-webkit-box-shadow: @style @c;
box-shadow: @style @c;
}
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
.box-shadow(@style, rgba(0, 0, 0, @alpha));
}
.box {
color: saturate(@base, 5%);
border-color: lighten(@base, 30%);
div { .box-shadow(0 0 5px, 30%) }
}
输出:
.box {
color: #fe33ac;
border-color: #fdcdea;
}
.box div {
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}
3、Webpack
Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
构建打包功能:
现在的前端开发基本上都是采用了模块化的开发方式,而且在代码中使用了大量的 es6+ 语言特性。但宿主浏览器中对新特性的支持不一。我们的代码无法直接运行在浏览器中,所以需要对代码进行构建打包,将代码编译成浏览器都可运行的代码。
也就是说浏览器的模块化运行,需要先编译打包才能运行,否则模块化语法浏览器它有可能不认识。比如:module是ES6引入模块化的运用,但目前浏览器并不能直接识别,需要打包工具打成ES5才可以(借助Browserify/webpack)。
题外话:
browserify / webpack : 是一个预编译模块的方案,相比于上面 ,这个方案更加智能。没用过browserify,这里以webpack为例。首先,它是预编译的,不需要在浏览器中加载解释器。另外,你在本地直接写JS,不管是 AMD / CMD / ES6 风格的模块化(五花八门的模块化规范下文会专门章节讲到),它都能认识,并且编译成浏览器认识的JS。这样就知道,Gulp是一个工具,而webpack等等是模块化方案。Gulp也可以配置seajs、requirejs甚至webpack的插件。
Webpack还可以通过 webpack.config.js配置文件来构建打包不同环境(调试,测试,生产)需要的不同配置的代码包(如是否缓存等)。配置文件样例如下:
我们可以将一些编译选项放在配置文件中,以便于统一管理:
创建 webpack.config.js 文件,代码如下所示:
app/webpack.config.js 文件
module.exports = {
entry: "./runoob1.js",
output: { path: __dirname, filename: "bundle.js" },
module: {
loaders: [{ test: /\.css$/,loader: "style-loader!css-loader"}]
}
};
接下来我们只需要执行 webpack 命令即可生成 bundle.js 文件。
安装webpack:
使用 cnpm 安装 webpack(在安装 Webpack 前,你本地环境需要支持 node.js):
cnpm install webpack -g
webpack打包demo:
webpack 根据模块的依赖关系进行静态分析,这些文件(模块)会被包含到 bundle.js 文件中。Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引和访问模块。 在页面启动时,会先执行 runoob1.js 中的代码,其它模块会在运行 require 的时候再执行。
接下来我们创建另外一个 js 文件 runoob2.js,代码如下所示:
app/runoob2.js 文件
module.exports = "It works from runoob2.js.";
更新 runoob1.js 文件,代码如下:
app/runoob1.js 文件
document.write(require("./runoob2.js"));
接下来我们使用 webpack 命令来打包:
webpack runoob1.js bundle.js
Hash: dcf55acff639ebfe1677
Version: webpack 1.12.13
Time: 52ms
Asset Size Chunks Chunk Names
bundle.js 1.55 kB 0 [emitted] main
[0] ./runoob1.js 41 bytes {0} [built]
[1] ./runoob2.js 46 bytes {0} [built]
在 app 目录下添加 index.html 文件,代码如下:
app/index.html 文件
总结,Webpack将JS等互相依赖,打包成最后只有一个js文件bundle.js。(Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求。)
4、部署
构建完成后,最后一步就是把前端资源发布到服务器了。假定我们的前端项目都是完全的前后端分离的,这意味着前端的资源需要和服务端分开部署。
比如,我们为专门准备一个 OSS 服务器用来部署入口文件,准备另一个 OSS 服务器部署 js、css 和图片等资源。
// package.json
"scripts": {
// 假定我们的部署逻辑在deploy.js中
"deploy": "node deploy.js"
}
部署我们会用到两个 npm 包,一个是 vinyl-ftp,专门用以登录我们的 OSS 服务器,另一个包是 vinyl-fs,用来将本地的资源发布到远程服务器。最后我们在 package.json 文件中配置 deploy 命令。部署操作只需要执行 npm run deploy 即可。
5、自动化测试
三、模块化
我们在上面一直提到模块化这个词,可谓本文的关键词。首先,小马推荐一篇模块化介绍的好文,点这里。后面我们来揭开下模块化这个面纱。
模块化规范:
1、CommonJs
语法的服务器端实现需要借助node.js,也可以说该module语法是node的语法不是JavaScript的语法。最终需要使用node app.js 跑起JS代码。
当然现在的VUE和小程序等前端工程项目貌似都是支持这个语法的。(值得注意的是,nodejs和vue虽然都是JS写的,前者是后端语言,后者是前端框架但vue的vue-cli脚手架--模块化运行还是要依赖nodejs,并依赖webpack打包编译才可以被浏览器直接运行。)
浏览器端的module语法实现需要借助Browserify等打包工具。需要npm下载Browserify对app.js进行打包成新的js文件才能被HTML正常引入。如下。
《nodejs中exports和module.exports的区别》
2、AMD
3、CMD
4、ES6模块化
再次感谢《前端模块化详解》作者。本文就到这了,小马时间和水平有限,不到之处望指点,bye。
彩蛋时间:
用闭包实现的一个简单的模块化。