前端工程化

[TOC]

什么是前端工程化

  • 前端工程化:将复杂的前端应用模块化、组件化、规范化、自动化的一个过程。

  • 解决的问题:做到多人协作的高效性;做到项目的可维护性;提高项目的开发质量;

一、模块化

模块化是针对文件层面,将大文件拆分成互相依赖的小文件,再进行统一的拼装和加载。

1.JS模块化

1.1 CommonJs

服务器端javascript模块化解决方案,适用于同步模块加载。NodeJs是CommonJs规范的主要践行者。

CommonJs用同步的方式加载模块,在服务端,模块文件都存在本地磁盘,读取非常快。但是在浏览器端,限于网络原因,更合理的方式是采用异步加载。

// 定义模块math.js
var basicNum = 0;
function add(a, b) {
  return a + b;
}
module.exports = { //在这里写上需要向外暴露的函数、变量
  add: add,
  basicNum: basicNum
}

// 引用自定义的模块时,参数包含路径,可省略.js
var math = require('./math');
math.add(2, 5);

// 引用核心模块时,不需要带路径
var http = require('http');
http.createService(...).listen(3000);

1.2 AMD 和require.js

AMD采用异步方式加载模块,模块的加载不影响后续语句的运行。所有依赖这个模块的语句,都统一定义在一个回调函数中,等到加载完成后,这个函数才会运行。require.js实现AMD规范的模块化:用require.config()指定引用路径,用define()定义模块,用require()加载模块。

首先需要引入require.js和入口文件main.js。main.js中配置require.config()并规定项目中用到的基础模块。

/** 网页中引入require.js及main.js **/
/** data-main 表示指定的js将在加载完require.js后处理,并且require会默认的将data-main指定的js作为根路径 */
<script src="js/require.js" data-main="js/main"></script>

/** main.js 入口文件/主模块 **/
// 首先用config()指定各模块路径和引用名
require.config({
  baseUrl: "js/lib",
  paths: {
    "jquery": "jquery.min",  //实际路径为js/lib/jquery.min.js
    "underscore": "underscore.min",
  }
});
// 执行基本操作
require(["jquery","underscore"],function($,_){
  // some code here
});

引用模块的时候,将模块名放在[ ]中作为require()的第一参数;如果定义的模块本身也依赖其他模块的时候,需要将它们放在[ ]中作为define()的第一参数。

// 定义math.js模块
define(function () {
    var basicNum = 0;
    var add = function (x, y) {
        return x + y;
    };
    return {
        add: add,
        basicNum :basicNum
    };
});
// 定义一个依赖underscore.js的模块
define(['underscore'],function(_){
  var classify = function(list){
    _.countBy(list,function(num){
      return num > 30 ? 'old' : 'young';
    })
  };
  return {
    classify :classify
  };
})
// 引用模块,将模块放在[]内
require(['jquery', 'math'],function($, math){
  var sum = math.add(10,20);
  $("#sum").html(sum);
});

1.3 CMD和sea.js

CMD是另一种js模块化方案,它与AMD和类似,不同点在于:AMD推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行。此规范是在推广sea.js过程中产生的。

/** AMD写法 **/
define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
     // 等于在最前面声明并初始化了要用到的所有模块
    a.doSomething();
    if (false) {
        // 即便没用到某个模块 b,但 b 还是提前执行了
        b.doSomething()
    } 
});
/** CMD写法 **/
define(function(require, exports, module) {
    var a = require('./a'); //在需要时申明
    a.doSomething();
    if (false) {
        var b = require('./b');
        b.doSomething();
    }
});
/** sea.js **/
// 定义模块 math.js
define(function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        return a+b;
    }
    exports.add = add;
});
// 加载模块
seajs.use(['math.js'], function(math){
    var sum = math.add(1+2);
});

1.4 UMD

UMD允许在环境中同时使用AMD和CommonJs规范。

(function(define) {
    define(function () {
        var helloInLang = {
            en: 'Hello world!'
        };

        return {
            sayHello: function (lang) {
                return helloInLang[lang];
            }
        };
    });
}(
    typeof module === 'object' && module.exports && typeof define !== 'function' ?
    function (factory) { module.exports = factory(); } :
    define
));

1.5 ES6 Module

ES6 的模块功能汲取了CommonJS 和 AMD 的优点,拥有简洁的语法并支持异步加载,并且还有其他诸多更好的支持。(例如导入是实时只读的。(CommonJS 只是相当于把导出的代码复制过来))

// CommonJS代码
// lib/counter.js
var counter = 1;
function increment() {
  counter++;
}
function decrement() {
  counter--;
}
module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement
};
// src/main.js
var counter = require('../../lib/counter');
counter.increment();
console.log(counter.counter); // 1
// 使用 es6 modules 通过 import 语句导入
// lib/counter.js
export let counter = 1;
export function increment() {
  counter++;
}
export function decrement() {
  counter--;
}
// src/main.js
import * as counter from '../../counter';
console.log(counter.counter); // 1
counter.increment();
console.log(counter.counter); // 2

1.5.1 ES6模块与CommonJs模块的差异
  1. CommonJS模块输出的是一个值得拷贝,ES6输出的是值得引用。
    • CommonJS模块输出的是值得拷贝,一旦输出一个值,模块内部的改变影响不到这个值。
    • ES6模块是动态引用,变量会随着模块的改变而改变。
  2. CommonJS模块是运行时加载,ES6是编译时输出接口。
    • 运行时加载:CommonJS模块就是对象;在输入时先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为"运行时加载"。
    • 编译时加载:ES6模块不是对象,而是通过export命令格式显示指定输出的代码,在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为"编译时加载"。

2.CSS的模块化

在less、sass、stylus等预处理器的import/mixin特性支持下实现、css modules。

虽然SASS、LESS、Stylus等预处理器实现了CSS的文件拆分,但没有解决CSS模块化的一个重要问题:选择器的全局污染问题;

CSS in JS是彻底抛弃CSS,使用JS或JSON来写样式。这种方法很激进,不能利用现有的CSS技术,而且处理伪类等问题比较困难;

CSS Modules 原理:使用JS 来管理样式模块,它能够最大化地结合CSS生态和JS模块化能力,通过在每个 class 名后带一个独一无二 hash 值,这样就不有存在全局命名冲突的问题了。

webpack 自带的 css-loader 组件,自带了 CSS Modules,通过简单的配置即可使用。

{
    test: /\.css$/,
    loader: "css?modules&localIde   ntName=[name]__[local]--[hash:base64:5]"
}

二、组件化

从UI拆分下来的 每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件。

模块化只是在文件层面上,对代码或资源的拆分;而组件化是在设计层面上,对UI(用户界面)的拆分。

其实,组件化更重要的是一种分治思想

Keep Simple. Everything can be a component.

这句话就是说页面上所有的东西都是组件。页面是个大型组件,可以拆成若干个中型组件,然后中型组件还可以再拆,拆成若干个小型组件,小型组件也可以再拆,直到拆成DOM元素为止。DOM元素可以看成是浏览器自身的组件,作为组件的基本单元。

三、规范化

规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。

  • 目录结构的制定
  • 编码规范
  • 前后端接口规范
  • 文档规范
  • 组件管理
  • Git分支管理
  • Commit描述规范
  • 定期CodeReview
  • 视觉图标规范

四、自动化

任何简单机械的重复劳动都应该让机器去完成。

  • 图标合并
  • 持续集成
  • 自动化部署
  • 自动化构建
  • 自动化测试
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容

  • 今天说一说前端的工程化,工程化大概包括模块化,组件化,自动化,规范化。在项目的启动之前,我们做好这一系列的工程...
    Osenki阅读 719评论 0 4
  • 一、模块化相关规范 1.模块化概述 传统开发模式的主要问题: 命名冲突,文件依赖 通过模块化解决上述问题: 模块化...
    coder_shen阅读 301评论 0 0
  • 前端工程本质上是软件工程的一种。软件工程化关注的是性能、稳定性、可用性、可维护性等方面,注重基本的开发效率、运行效...
    黎贝卡beka阅读 9,603评论 1 7
  • 1.模块化的相关规范 1.能够了解2.了解webpack3.了解使用Vue单文件组件4.能够搭建Vue脚手架5.掌...
    Scincyc阅读 657评论 0 0
  • 1、从 URL 输入到页面展现背后发生的事 1. 从 URL 输入到页面展现背后发生了什么事? 1.在浏览器输入 ...
    没糖_cristalle阅读 833评论 0 0