前端发展演进

2/21/2020

工程化即系统化,模块化,规范化的过程。如果说计算机科学要解决的是系统的某个具体问题,或者更通俗点说是面向编码的,那么工程化要解决的是如何提高整个系统生产效率。

# 前端发展历史

  1. 后端为主的传统时代

    不分前后端,页面由JSP,ASP,PHP等服务端生成,浏览器负责展示。比如Servlet和JSP

    传统时代

    后来后端再次发展,后端服务规范化,分层化,出现了许多优秀的架构。比如Strusts,SpringMVC等。

    传统时代1

  2. 前后端分离为主的时代

    随着ajax技术发展,前后端开始分离,前端负责页面渲染,输出和输入信息,后端负责逻辑处理,两者之间通过前后端接口的方式沟通。

    前后端分离

    后来前端发展,前端出现了AngularJS、React、Vue等大量前端框架,使得前端组织结构更加模块化,规范化。

    前后端分离1

  3. 全栈时代

    Node.js的兴起,带来了JavaScript全栈化开发的模式。

# 模块化

简单来说,模块化就是将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载。这样便于多人协作

# JS模块化

JavaScript社区制定了一些模块加载方案,如CommonJS、AMD和CMD等,某些框架也会有自己模块系统,比如Angular1.x。

现在随着ES6的出现,使用大一统的ES6规范,基本上可以取代现有的CommonJS和AMD规范。

# CSS模块化

SASS,LESS等CSS预处理的出现实现了CSS文件的模块化。但需要注意CSS全局污染问题。

# 资源模块化

除了JS,CSS之外,其他资源,比如图片,字体,vue单文件等也应该模块化。利用Webpack的强大功能即可解决。

# 组件化

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

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

目前市面上的组件化框架很多,主要的有Vue (opens new window)React (opens new window)Angular (opens new window)

# 规范化

通过遵守统一规范,能让代码更好维护。

某些规范化,比如:

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

其中编码规范,就有ESLint (opens new window)和StyleLint等强制措施。

# 自动化

更多具体的内容,可参考传送门1 (opens new window)传送门2 (opens new window)

# NPM

NPM即Node Package Manager,是NodeJS的包管理和分发工具。而NodeJS简单来说就是运行在服务端的JavaScript的运行环境。

NPM是随着NodeJS一起安装的,具体安装流程可参考传送门 (opens new window)

NPM的主要应用场景有以下几种:

  • 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
  • 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
  • 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。

NPM

以Java开发者视角来看NPM的话,它相当于Maven。

以Python开发者视角来看NPM的话,它相当于Conda。

# ES6

ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

ES6

  1. ECMAScript和JavaScript的关系

    简单来说,ECMAScript是浏览器脚本语言的标准,JavaScript是浏览器语言标准的实现之一(另外的 基于ECMAScript标准实现 还有 JScript 和 ActionScript)。日常情况下,两个词是可以互换的。

    这有些类似于J2EE的13规范和各大规范实现框架关系。前者一个是规范,后者一个是实现。

  2. ES6与ECMAScrip2015的关系

    2011 年,ECMAScript 5.1 版发布后,就开始制定 6.0 版了。因此,ES6 这个词的原意,就是指 JavaScript 语言的下一个版本。但是由于某些原因,直到2015年6月,才正式发布ES6的第一个版本,正式名称为《ECMAScript 2015 标准》(简称 ES2015)。该标准在每年6月正式发布一次。2016年6月,发布《ECMAScript 2016 标准》(简称 ES2016);2017年6月发布《ECMAScript 2017标准》(简称 ES2017)。

    因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等。

  3. ECMAScript历史

    • ECMAScript1.0是1997年发布
    • ECMAScript2.0是1998年发布
    • ECMAScript3.0是1999年发布,在业界得到广泛支持,成为通行标准,奠定了 JavaScript 语言的基本语法。初学者刚开始学习JavaScript,其实就是在学习3.0版本
    • ECMAScript 4.0 由于某些原因发布失败
    • ECMAScript 5.0 是2009年发布,也就是ES5
    • ECMAScript 6.0 是2015年发布,之后每年6月一个小版本的跨越。2016年发布ECMAScript 6.1(ES2016),以此类推
  4. Babel转码器

    Babel (opens new window) 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。主要现在浏览器主要支持ES5语法,为保证代码能够顺利运行,我们需要用转换器将ES6代码转化为浏览器支持的ES5语法。

ES6的内容也挺多的,不是一时半会就能学习和整理完的,但是先要对其有基本的了解,遇到不懂可以边查边了解。在未来再进行基本的内容学习和整理。

具体更多内容,可参考传送门 (opens new window)

# Webpack

Webpack是一个流行的前端项目构建工具(打包工具),提供友好的模块化支持,代码压缩混淆,处理js兼容,性能优化等功能。目前大多数前端项目都是基于Webpack打包构建的。

what-is-webpack

具体更多内容,可参考传送门1 (opens new window)传送门2 (opens new window)

# Webpack的基本使用

通过一个简单列表隔行变色项目,来介绍Webpack。

创建一个空白目录,通过npm init -y来初始化包管理文件package.json。然后运行npm i jquery -S命令安装JQuery,然后通过ES6的模块化方式,实现隔行变色的效果。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <script src="./index.js"></script>
  </head>
  <body>
    <ul>
      <li>这是第1个li</li>
      <li>这是第2个li</li>
      <li>这是第3个li</li>
      <li>这是第4个li</li>
      <li>这是第5个li</li>
      <li>这是第6个li</li>
      <li>这是第7个li</li>
      <li>这是第8个li</li>
      <li>这是第9个li</li>
    </ul>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// index.js
import $ from 'jquery'

$(function(){
    $('li:odd').css('backgroundColor', 'blue')
    $('li:even').css('backgroundColor', 'lightblue')
})
1
2
3
4
5
6
7

webpack引入原因

结果,我们发现,浏览器运行时,并没有隔行变色的效果,这是因为在浏览器里不支持ES6的模块化语法,这时候,我们就需要通过webpack打包工具,将我们ES6的模块化语法,转化为浏览器能够兼容的js。

# 安装和配置webpack

接下来,我们通过在项目中安装和配置webpack的方式,解决问题。

首先运行npm i webpack webpack-cli -D命令,安装webpack。然后在项目的根目录下,创建webpack.config.js的webpack配置文件。在配置文件中添加以下配置:

module.exports = {
    mode:'development' //mode 用来指定构建模式
}
1
2
3

接着在package.json文件中的scripts的节点中,新增dev运行脚本:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack"
}
1
2
3
4

最后在终端运行npm run dev命令,启动webpack进行打包。

> webpack

Hash: ce25f383883ee2f00d11
Version: webpack 4.41.6
Time: 690ms
Built at: 2020-02-20 14:29:44
  Asset     Size  Chunks             Chunk Names
main.js  314 KiB    main  [emitted]  main
Entrypoint main = main.js
[./src/index.js] 145 bytes {main} [built]
    + 1 hidden module
1
2
3
4
5
6
7
8
9
10
11

会发现,webpack将index.js文件打包成main.js文件,将其放置在dist文件夹下,然后将其引入index.html中,再在浏览器运行时,发现隔行变色的效果出现了。

webpack引入原因1

可以见得webpack的将我们基于ES6模块化的代码打包为浏览器可兼容的js脚本。

# webpack配置文件项说明

  • 配置打包的入口和出口

    webpakc4.x版本中默认:

    • 打包入口文件为src/index.js
    • 打包输出文件为dist/main.js

    如果想要修改打包的入口与出口,只要配置中添加entryoutput节点。

    const path = require('path')
    
    module.exports = {
        mode:'development', //mode 用来指定构建模式
        entry:path.join(__dirname,'./src/index.js'), //打包入口文件路径
        output:{
            path:path.join(__dirname,'./dist'),//输出文件的存放路径
            filename:'bundle.js' //输出文件名称
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 配置自动打包功能

    运行npm i webpack-dev-server -D,安装项目支持自动打包工具。然后修改package.json的script脚本命令:

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server"
    }
    
    1
    2
    3
    4

    当执行npm run dev后,在浏览器访问http://localhost:8080地址,即可看到项目结构,点击src,就会访问到index.html文件,当其中内容改变时,可以实时打包更新。

    还可以配置自动打包相关参数,比如ip地址,端口等。

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server --open --host 127.0.0.1 --port 8888"
    }
    
    1
    2
    3
    4
    • --open 用于打包完成后自动打开浏览器页面
    • --host 配置ip地址
    • --port 配置端口
  • 配置插件之 html-webpack-plugin

    在访问http://localhost:8080地址时,发现访问的是项目的结构,我们能通过安装插件的方式,安装生成浏览页面的插件。

    运行npm i html-webpack-plugin -D,然后在webpack.config.js,添加如下配置信息:

    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    const htmlPlugin = new HtmlWebpackPlugin({ //创建插件实例对象
        template:'./src/index.html', //指定模板文件
        filename:'index.html' //指定生成的文件的名称,该文件存在内存中,在目录中不显示
    }) 
    
    module.exports = {
        mode:'development', //mode 用来指定构建模式
        entry:path.join(__dirname,'./src/index.js'), //打包入口文件路径
        output:{
            path:path.join(__dirname,'./dist'),//输出文件的存放路径
            filename:'bundle.js' //输出文件名称
        },
        plugins:[htmlPlugin] //plugins数组为打包期间用到的插件列表
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

# Webpack的加载器

webpack默认只能打包处理.js后缀结尾的模块。其他非.js后缀结果的模块,webpack默认处理不了,需要调用loader加载器才能正常打包,否则会报错。

loader加载器可以协助webpack打包处理特定的文件模块,比如

  • css-loader可以打包处理.css相关的文件
  • url-loader可以打包处理css中与url路径相关的文件
  • vue-loader可以打包处理.vue相关的文件

webpack-loader调用过程

# 打包处理css文件

  1. 安装处理css文件的loader,运行npm i style-loader css-loader -D

  2. 在webpack.config.js的module中添加rules数组节点,添加loader规则

    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    const htmlPlugin = new HtmlWebpackPlugin({ //创建插件实例对象
        template:'./src/index.html', //指定模板文件
        filename:'index.html' //指定生成的文件的名称,该文件存在内存中,在目录中不显示
    }) 
    
    module.exports = {
        mode:'development', //mode 用来指定构建模式
        entry:path.join(__dirname,'./src/index.js'), //打包入口文件路径
        output:{
            path:path.join(__dirname,'./dist'),//输出文件的存放路径
            filename:'bundle.js' //输出文件名称
        },
        plugins:[htmlPlugin], //plugins数组为打包期间用到的插件列表
        //所有loader加载器的匹配规则
        module:{
            rules:[
                {test:/\.css$/,use:['style-loader','css-loader']}
            ]
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23

    注意:

    • use数组中指定的loader顺序是固定的
    • 多个loader的调用顺序的:从后往前调用

# 打包处理图片文件

  1. 安装处理图片文件的loader,运行npm i url-loader file-loader -D

  2. 在webpack.config.js的module中添加rules数组节点,添加loader规则

    module.exports = {
        mode:'development', //mode 用来指定构建模式
        entry:path.join(__dirname,'./src/index.js'), //打包入口文件路径
        output:{
            path:path.join(__dirname,'./dist'),//输出文件的存放路径
            filename:'bundle.js' //输出文件名称
        },
        plugins:[htmlPlugin], //plugins数组为打包期间用到的插件列表
        //所有loader加载器的匹配规则
        module:{
            rules:[
                {test:/\.css$/,use:['style-loader','css-loader']},
                {test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,use:'url-loader?limit=16940'}
            ]
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    注意:

    • 当只调用一个加载器时,use可以不为数组
    • ?之后的是loader的参数项,limit用来指定图片大小,单位是字节,只有小于limit大小的图片,才会被转为base64图片

# 打包处理js文件中高级语法

  1. 安装babel转换器相关的包npm i babel-loader @babel/core @babel/runtime -D

  2. 安装babel语法插件相关的包:npm i @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D

  3. 在项目根目录中,创建babel配置文件babel.config.js,初始化配置:

    module.exports = {
        presets:['@babel/preset-env'],
        plugins:['@babel/plugin-transform-runtime','@babel/plugin-proposal-class-properties']
    }
    
    1
    2
    3
    4
  4. 在webpack.config.js的module中添加rules数组节点,添加loader规则

    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    const htmlPlugin = new HtmlWebpackPlugin({ //创建插件实例对象
        template:'./src/index.html', //指定模板文件
        filename:'index.html' //指定生成的文件的名称,该文件存在内存中,在目录中不显示
    }) 
    
    module.exports = {
        mode:'development', //mode 用来指定构建模式
        entry:path.join(__dirname,'./src/index.js'), //打包入口文件路径
        output:{
            path:path.join(__dirname,'./dist'),//输出文件的存放路径
            filename:'bundle.js' //输出文件名称
        },
        plugins:[htmlPlugin], //plugins数组为打包期间用到的插件列表
        //所有loader加载器的匹配规则
        module:{
            rules:[
                {test:/\.css$/,use:['style-loader','css-loader']},
                {test:/\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,use:'url-loader?limit=16940'},
                {test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
            ]
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    注意:

    • exclude为排除项,表示babel——loader不需要处理node_modules中的js文件
Last Updated: 8/23/2023, 2:39:40 PM