通过参考网上的一些构建方法,当然也在开发过程中进行了一番实践,最终搭建了一套适用于当前多页应用的构建方案,当然该方案还处于draft版本,会在后续的演进过程中不断的优化。

个人觉得该方案的演进过程相对于成果而言更值得记录。但在此之前,我们先简单介绍下项目的整体架构,这样大家会更明白为什么要采用这样的构建方式。下图列出了用户在浏览器中输入url到页面ready的过程,可以看出这是一个典型的服务端直出架构,其中作为前端工程师的我们主要关注点是放在浏览器端以及Node层。在Node层,我们对koa的进行了封装,并采用了类似于eggjs的MVC架构,同时使用pug作为模板引擎,技术栈其实并不复杂。

V0.0.1:使用webpack对前端资源进行构建

在构建过程中要做什么事呢?相信不同的人有不同的见解:

  • 对静态资源进行压缩,减少传输字节;
  • 为避免浏览器读取了旧的缓存文件,需要为静态资源添加MD5戳;
  • 为CSS属性自动添加vendor prefix;
  • ......

上面所列出的事项也是我们在构建过程中所需要考虑的。在项目早期的构建方案中,我们选择使用webpack作为构建工具,原因其实很简单:功能强大、用的人多,所以一拍脑袋就选择它了。当然,webpack也确实不负众望,通过它,我们可以像写Node一样直接引入其他的文件,在使用前期确实给我们带来了很多的便捷。

但是我们的项目毕竟和webpack主流的使用场景,如React、Vue等项目还是有很大的不同之处,在使用webpack的过程中陆续出现了一些水土不服的地方,虽然都最后都通过一些方式解决了,但是这也促使我们在思考,是否有其他更合适的方案。

问题一:

如何让webpack打包所有资源文件?

解决方法:

webpack会将entry作为入口起点,找到所有依赖项并对其进行构建。由于webpack只认识JavaScript文件,所以对于非JavaScript文件需要使用loader将其转为webpack能够处理的模块。所以说,如果某个资源文件需要被webpack构建,那么这个资源文件必须是从entry可达的。对我们的项目来说,最理想的情况是以pug模板文件作为入口,但是由于pug模板文件需要的数据是从server获取的,而在构建阶段是不可知的,所以,只能退而求其次,使用JavaScript文件作为入口。

对于不同类型的文件,我们采用了不同的策略:

  • 对于图片,我们使用了webpack提供的require.context方法,它可以让我们使用正则的方式来引入相应的模块。所以我们添加了下述文件,并将其置于webpack的entry属性中。
require.context('./public', true, /\.*\.(jpg|png|jpeg|gif|ico)$/i)
  • 对于css文件,当然也可以采用上述的方式,但是这会将所有的css编译到一个文件中,导致生成的文件过大,从而使页面加载耗时较长。所以我们只能选择在相应的JavaScript文件中添加 import './xxxx.less' 来告诉webpack:你需要构建xxxx less/css文件了。这样做功能是实现了,但是却并不优雅,同时也会使JavaScript变得不纯粹,也没办法被其他不用webpack作为构建工具的项目所重用了。

问题二:

在Node从server获取数据后,会将pug模板渲染成html并将其发送回浏览器端,那么在模板中如何保持对静态资源的引用呢?因为构建工具会为所有的资源文件添加MD5戳,所以我们在编码时并不知道确切的文件名是什么。

解决方法:

利用webpack-manifest-plugin插件,它会在webpack构建完成后生成一个manifest.json文件,该文件会列出原始文件名与构建后的文件名之间的匹配关系。通过将manifest.json作为参数传入pug的render方法中,这样在pug模板中就可以通过类似于 img(src=manifest["logo.png"]) 的方式来保持对静态资源的引用。

V1.0.0-beta:使用gulp+webpack对前端资源进行构建

问题总是有方法解决的,但是这样写起来总有一些别扭,也感觉很不优雅,这致使我们思考webpack是否真的适用于我们的项目。通过一番讨论,最终决定尝试使用gulp+webpack的方式进行构建。

  1. 利用webpack构建JavaScript资源,可以方便的利用webpack模块的思想,使得JavaScript之间相互引用变得简单、便捷;
  2. 利用gulp构建css, images等其他资源。

使用webpack对JavaScript进行构建时,为了不至于每次添加一个新文件,都要修改webpack的配置,所以我们写了一个方法将所有的JavaScript都放入webpack的entry属性中。

function entries(globPath) {
const files = glob.sync(globPath);
let key, name, ext, entries = {}; for (let file of files) {
ext = path.extname(file);
name = path.basename(file, ext);
if (name.startsWith('_')) {
continue;
} entries[name] = path.join(__dirname, file);
}
return entries
}

使用时,只需要在globPath中输入指定的js路径就可以了,如

let webpackConfig = {
entry: entries('./public/**/*.js'),
}

而在实际的开发中我们发现,有一些JavaScript文件存在的目的就是被其他文件引用,例如一些helper方法,它们是不会作为webpack的entry存在的,所以我们在entries方法中只寻找不是以下划线(_)开头的JavaScript文件,因此对于一些只有helper方法的JavaScript文件,只需要将其文件名以_开头,这样就不会被添加到webpack的entry属性中了,这也算是该构建方案中的一个小彩蛋~~~

在使用gulp对其他资源的构建过程中,我们用到了很多成熟的gulp插件,其中我认为比较重要的是gulp-rev和gulp-rev-replace。其中gulp-rev插件用来为css、images等资源文件添加MD5戳并生成相应的manifest.json文件,同时搭配使用gulp-rev-replace插件将pug、css等文件中存在于manifest.json里的文件名进行替换,这样我们在pug模板中引用资源文件就可以直接写 img(src=logo.png) 而不需要像以前那么复(chou)杂(lou)了。

再说一个题外话,其实在使用gulp-rev+gulp-rev-replace插件之前,我们尝试使用过gulp-md5-plus插件。gulp-md5-plus插件使用起来超级方便,它可以添加MD5戳,也可以替换文件名,但是该插件暂不支持添加自定义前缀的功能,而这个功能对我们确实必须的。因为在生产环境中,所有的资源文件会放到CDN上,而测试环境中的资源文件则放在对应的测试服务器上,所以说,同样的一张图片,在测试环境的地址可能是public/images/logo.png,而生产环境却是//cdn.demo.com/images/logo.png,所以我们需要支持自定义前缀功能,并使用类似下述的代码为其添加前缀 var prefix = process.env.NODE_ENV === 'production' ? '//cdn.demo.com/': '/public/' 。

写在最后:

上述构建方案也许不是那么完美,但是对于当前的项目来说,确是一个相对而言较为合适的。当然也不排除后续该方案会被其他更优雅的方案所替代。但是通过这么多次的尝试、重构,才真正体会到了什么叫“适合的才是最好的

用gulp+webpack构建多页应用——记一次Node多页应用的构建过程的更多相关文章

  1. 做一个gulp+webpack+vue的单页应用开发架子

    1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...

  2. gulp & webpack整合

    为什么需要前端工程化? 前端工程化的意义在于让前端这个行业由野蛮时代进化为正规军时代,近年来很多相关的工具和概念诞生.好奇心日报在进行前端工程化的过程中,主要的挑战在于解决如下问题:✦ 如何管理多个项 ...

  3. nodejs+gulp+webpack基础知识

    nodejs+gulp+webpack基础知识 2019年08月22日 11:49:40 天府云创 阅读数 22   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文 ...

  4. gulp + webpack + sass 学习

    笔记: new webpack.optimize.CommonsChunkPlugin 核心作用是抽离公共代码,chunks:['index.js','main.js'] 另一个作用就是单独生成一个j ...

  5. gulp+webpack+vue

    gulp+webpack+vue 章节目录 1.目标 2.实现 2.1合并库文件 2.2组织业务代码 2.3打包开发代码 2.4使用webpack-dev-server和热替换插件HotModuleR ...

  6. grunt,gulp,webpack前端打包工具的特性

    1.http://www.cnblogs.com/lovesong/p/6413546.html (gulp与webpack的区别) 2.http://blog.csdn.net/qq_3231263 ...

  7. 万能js实现翻页,动态生成内容自动翻页,兼容各种浏览器(已测试)----神器版!

    转--http://www.2cto.com/kf/201402/277535.html 万能js实现翻页,动态生成内容自动翻页,兼容各种浏览器(已测试)----神器版! 2014-02-11     ...

  8. C# 翻页设计:首页,上一页,下一页,末页 ,跳转

    int pageSize = 0; //每页显示行数 int nMax = 0; //总记录数 int pageCount = 0; //页数=总记录数/每页显示行数 int pageCurrent ...

  9. React + Node 单页应用「二」OAuth 2.0 授权认证 & GitHub 授权实践

    关于项目 项目地址 预览地址 记录最近做的一个 demo,前端使用 React,用 React Router 实现前端路由,Koa 2 搭建 API Server, 最后通过 Nginx 做请求转发. ...

随机推荐

  1. 孤荷凌寒自学python第四十八天通用同一数据库中复制数据表函数最终完成

    孤荷凌寒自学python第四十八天通用同一数据库中复制数据表函数最终完成 (完整学习过程屏幕记录视频地址在文末) 今天继续建构自感觉用起来顺手些的自定义模块和类的代码. 今天经过反复折腾,最终基本上算 ...

  2. crontab-用于设置周期性被执行的指令

    一个很好用的工具. 参考文章: [入门] http://baike.baidu.com/view/1229061.htm [进阶] http://blog.csdn.net/tianlesoftwar ...

  3. sublime3 Package Control和 中文安装

    sublime3中文版需要使用PackageControl,所以首先需要安装PackageControl 一.PackageControl安装: 1.点击Preferences > Browse ...

  4. 201621123034 《Java程序设计》第6周学习总结

    作业06-接口.内部类 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 注1:关键词与内容不求多 ...

  5. jQuery选择器之元素选择器

    元素选择器:根据给定(html)标记名称选择所有的元素. 描述: $('element') 搜索指定元素标签名的所有节点,这是一个合集的操作.同样的也有原生方法getElementsByTagName ...

  6. Centos 6.5 HISTSIZE更改

    通过 更改 /etc/profile 中的HISTSIZE值,改完之后,执行source /etc/profile  和echo $HISTSIZE,结果还是之前的HISTSIZE值, 解决办法:执行 ...

  7. [CF191C]Fools and Roads

    题目大意:有一颗$n$个节点的树,$k$次旅行,问每一条被走过的次数. 题解:树上差分,$num_x$表示连接$x$和$fa_x$的边被走过的次数,一条路径$u->v$,$num_u+1,num ...

  8. 【BestCoder #44】

    因为这场比赛,我愉快地逃掉了晚自修. T1一开始各种SillyB,忘了40%的最低限制... T2各种想吐槽... 明明OJ警告说%lld是不行的我就换成%I64D(上面写这样的)... 结果各种WA ...

  9. Batting Practice LightOJ - 1408

    Batting Practice LightOJ - 1408(概率dp) 题意:有无限个球,进球的概率为p,问你连续不进k1个球或者连续进k2个球需要使用的球的个数的期望 思路: \(定义f[i]表 ...

  10. 一种简单高效的音频降噪算法示例(附完整C代码)

    近期比较忙, 抽空出来5.1开源献礼. 但凡学习音频降噪算法的朋友,肯定看过一个算法. <<语音增强-理论与实践>> 中提及到基于对数的最小均方误差的降噪算法,也就是LogMM ...