web前端工程化/构建自动化

时间:2020-06-06 17:03:42   收藏:0   阅读:60

前端工程化

前端工程化的概念在近些年来逐渐成为主流构建大型web应用不可或缺的一部分,在此我通过以下这三方面总结一下自己的理解。

  1. 为什么需要前端工程化。

  2. 前端工程化的演化。

  3. 怎么实现前端工程化。

 

为什么需要工程化

  随着近些年来前端技术的不断发展,越来越多复杂的业务放在了前端,前端不再是以前几个HTML + CSS + javascript就能解决的了。业务复杂了,需要维护的代码量就自然多了,如此一来,前端代码的可靠性,可维护性,可拓展性,以及前端web应用的性能,开发效率等等各方面就成了不得不考虑的问题。

  于是我们就产生了前端工程化这个概念,来解决这些问题。现阶段的前端工程化,需要考虑到各个方面,包括但不限于以下这几点:

提升开发效率

 

优化性能

 

提高代码质量

 

前端工程化的发展

<script> 直接引入加载

  在没有引入模块化的概念之前,前端往往需要手动处理js文件的依赖关系,例如;bootstartp 依赖 jquery,就需要在引入bootstrap之前引入jquery

1 <script src="src/jquery.min.js" ></script>
2 <script src="src/bootstrap.min.js" ></script>

 

  如果引入js文件顺序错了则会报错。 乍一看似乎没什么难度呀,是人都能分清是吧。那么请看下面这种情况:
  有 a.js, b.js, c.js, d.js, e.js 五个文件,其中

  那么根据以上关系,请按正确顺序引入js文件(黑人问号???)。当然,事实上也并不难区分其优先级,逐级递推就很快可以推断出引入顺序为 e,d,b,a,c。


  毫无疑问,对于稍微复杂点的web工程,存在复杂依赖情况是极有可能发生的,并且把时间耗费在管理依赖关系上也不值当。

  所以就诞生了前端模块化

 

模块化标准(AMD,CMD,ES6 Module)

  经历了混乱加载的黑历史,我们终于迎来了js的模块化,忽如一夜春风来,一夜之间冒出一堆模块化标准。

  其中具有代表性的模块加载器分别是是遵循AMD(Asynchronous Module Definition)规范的RequireJS ,还有淘宝玉伯开源的 遵循CMD(Common Module Definition)规范的 SeaJS。 两者除了遵循规范不一样之外,封装模块有差别之外,都各有所长,而且对旧版本浏览器的支持都相当完美。

  当然除了这两个,还有各类其他开发者开发的模块加载器,当真是一番群魔乱舞百家争鸣的盛世呀。在此就不一一细述了。

  下面有请我们的主角出厂: ES6 Module。 

  ES6 Module 是新一代javascript标准 ECMAScript 6 的新增特性,其语法和Python相似,比较简洁易用。另外,相比于其他模块加载器,ES6 Module 是语法级别的实现,其静态代码分析相比于其他框架会更快更高效,方便做代码检测。

1 // import 基本语法
2 import React from react;    //等价于 var React = require("react");
3 import { stat, exists, readFile } from fs;
4 // 等价于 
5 // var fs = require(‘fs‘);
6 // var stat = fs.stat, exists = fs.exists, readFile = fs.readFile;

 

  
  而且,且不论其API优劣,其语法与前面说的模块化有什么区别的,ES6 Module最大优点是显而易见的: 它是官方标准,而不是其他妖艳贱货第三方开发的框架/库。跟着有名分的原配混,毫无疑问是有前途更稳定的吧。 

  当然,缺点也是很明显的,不同于RequireJS,SeaJS 向下兼容到极致(ie6+),ES6 Module 的兼容性还未覆盖绝大部分浏览器,支持ES6 Module的浏览器寥寥无几,虽然可以通过babel进行语法转译,不过兼容性毕竟是硬伤,唯有时间能治愈。

熊猫办公 https://www.wode007.com/sites/73654.html

自动化构建工具(gulp,grunt)

  从描述可知,前端工程化需要做的事情,单凭人力一个一个去处理基本没有可能完成,那么,我们就需要学会使用工具,毕竟程序猿和猿之间最大的区别就是会不会使用工具。 

  grunt 和 gulp 就是自动化构建工具。我们通过安装对应的node_module,根据gulp/grunt 的API编写相对应的任务(如:css预处理,代码合并压缩,代码校验检查等任务,js代码转译),那么就可以生成我们想要的结果,完成前端工作流管理,极大程度地提高效率。其作用其实就相当于makefile 的make 操作,将手工操作自动化,其任务编写格式如下。

 1 // gulp scss预处理任务
 2 gulp.task(styles, function() {
 3   return gulp.src(src/styles/main.scss)
 4     .pipe(sass({ style: expanded }))
 5     .pipe(autoprefixer(last 2 version, safari 5, ie 8, ie 9, opera 12.1, ios 6, android 4))
 6     .pipe(gulp.dest(dist/assets/css))
 7     .pipe(rename({suffix: .min}))
 8     .pipe(minifycss())
 9     .pipe(gulp.dest(dist/assets/css))
10     .pipe(notify({ message: Styles task complete }));
11 });

 

 

模块化打包器(webpack)

  前面说了那么多SeaJS,RequireJS的模块化 ,又有gulp ,grunt的自动化处理,想必都有点觉得这前端工程化的技术栈也太繁琐了吧。

  那么现在,你可以统统不用管啦,让我们推出终极解决方案:Webpack。  

  相比于seajs / requirejs 需要在浏览器引入 sea.js 、require.js 的模块解析器文件,浏览器才能识别其定义的模块。 webpack不需要在浏览器中加载解释器,而是直接在本地将模块化文件(无论是AMD,CMD规范还是ES6 Module)编译成浏览器可识别的js文件。 

  另外,相对于gulp/grunt 的批处理工作流功能,webpack 也可以通过 loader、plugin的形式对所有文件进行处理,来实现类似的功能。 

  其主要工作方式是: 整个项目存在一个或多个入口js文件,通过这个入口找到项目的所有依赖文件,通过loader,plugin进行处理后,打包生成对应的文件,输出到指定的output目录中。可以说是集模块化与工作流于一身的工具

技术图片


  当然,webpack也并非银弹。工具没有好坏,只有适合与否。即便是webpack也并非适用于所有场合。 

  webpack 的最大特点是一切皆为模块,一切全包,最适和应用在SPA一站式应用场景。只有简单几个页面的情况下使用 webpack 反而可能会增加不必要的配置成本,反而直接用gulp或者其他工具处理代码压缩,css 预处理之类的工作会更加快捷易用。 

  另外,除了最主流的 webpack 之外,同性质的模块化打包器还有 browserIfy,以及百度的 fis ,由于对这两者了解不多,就不一一比较了。

 

使用 webpack 实现工程化

  废话少说,talk is easy , show me the code,我们来看看webpack是怎么工作的。以下是一个配置了webpack-dev-server的本地开发webpack配置文件。 具体可访问 github 地址 查看完整信息

 
 1 // webpack.dev.config.js
 2 let path = require(path),
 3       webpack = require(webpack);
 4 
 5 let resolve = path.resolve;
 6 let webRootDir = resolve(__dirname, ../);
 7 
 8 
 9 module.exports = {
10     entry: {                 // 入口文件,打包通过入口,找到所有依赖的模块,打包输出
11         main: resolve(webRootDir, ./src/main.js), 
12     },
13     output: {
14         path: resolve(webRootDir, ./build),  // 输出路径
15         publicPath: /build/,     // 公共资源路径
16         filename: [name].js      // 输出文件名字,此处输出main.js, babel-polyfill.js ,  视情况可以配置[name].[chunkhash].js添加文件hash, 管理缓存
17     },
18     module: {
19         rules: [   //模块化的loader,有对应的loader,该文件才能作为模块被webpack识别
20             {
21                 test: /\.js$/,
22                 loader: babel-loader,
23                 exclude: /node_modules/
24             },
25             {
26                 test: /\.(png|jpg|gif|svg|ico)$/,
27                 loader: file-loader,
28                 options: {
29                     name: [name].[ext]?[hash]
30                 }
31             },
32             {
33                 test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
34                 loader: file-loader
35             },
36             {
37                 test: /\.css$/,
38                 loader: style-loader!css-loader
39             },
40             {
41                 test: /\.scss$/,
42                 loader: style-loader!css-loader!autoprefixer-loader?{browsers:["last 5 version", "Firefox +
43                  15"]}!sass-loader?sourceMap&outputStyle=compressed
44             }
45         ]
46     },
47 
48     resolve: {
49         extensions: [.js],  // 定义后缀名 ,import时可以省略“.js”后缀
50         alias: {   // 别名。 如 import "./src/style/common.css"  ==> import "style/common.css"
51             components: resolve(webRootDir, ./src/components),
52             page: resolve(webRootDir, ./src/page),
53             style: resolve(webRootDir, ./src/style),
54             script: resolve(webRootDir, ./src/script),
55             static: resolve(webRootDir, ./static)
56         }
57     },
58 
59     devServer: { // webpack-dev-server 热加载的配置
60         host: 127.0.0.1,   //本地ip, 如需局域网内其他及其通过ip访问,配置"0.0.0.0"即可
61         port: 8080,
62         disableHostCheck: true,
63         historyApiFallback: true,
64         noInfo: true
65     },
66 
67     performance: {
68         hints: false
69     },
70 
71 }
72 
73 module.exports.devtool = #source-map
74 
75 /*插件*/
76 module.exports.plugins = (module.exports.plugins || []).concat([
77     // webpack 变量定义,,可在其他模块访问到该变量值,以便根据不同环境来进行不同情况的打包操作。
78     //  例如,在main.js 下 console.log( process.env.Node_ENV ) 输出 development字符串
79     new webpack.DefinePlugin({
80         process.env: {     
81             NODE_ENV: `"development"`
82         }
83     }),
84 
85 ])

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!