用gulp+webpack构建多页应用——记一次Node多页应用的构建过程
通过参考网上的一些构建方法,当然也在开发过程中进行了一番实践,最终搭建了一套适用于当前多页应用的构建方案,当然该方案还处于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的方式进行构建。
- 利用webpack构建JavaScript资源,可以方便的利用webpack模块的思想,使得JavaScript之间相互引用变得简单、便捷;
- 利用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多页应用的构建过程的更多相关文章
- 做一个gulp+webpack+vue的单页应用开发架子
1.目标 最近项目上的事情不多,根据我自己的开发习惯,决定开发一些简单的开发架子,方便以后事情多的时候直接套用.本文讲的一个gulp+webpack+vue的单页应用架子,想要达到的目的: 可以通过命 ...
- gulp & webpack整合
为什么需要前端工程化? 前端工程化的意义在于让前端这个行业由野蛮时代进化为正规军时代,近年来很多相关的工具和概念诞生.好奇心日报在进行前端工程化的过程中,主要的挑战在于解决如下问题:✦ 如何管理多个项 ...
- nodejs+gulp+webpack基础知识
nodejs+gulp+webpack基础知识 2019年08月22日 11:49:40 天府云创 阅读数 22 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文 ...
- gulp + webpack + sass 学习
笔记: new webpack.optimize.CommonsChunkPlugin 核心作用是抽离公共代码,chunks:['index.js','main.js'] 另一个作用就是单独生成一个j ...
- gulp+webpack+vue
gulp+webpack+vue 章节目录 1.目标 2.实现 2.1合并库文件 2.2组织业务代码 2.3打包开发代码 2.4使用webpack-dev-server和热替换插件HotModuleR ...
- grunt,gulp,webpack前端打包工具的特性
1.http://www.cnblogs.com/lovesong/p/6413546.html (gulp与webpack的区别) 2.http://blog.csdn.net/qq_3231263 ...
- 万能js实现翻页,动态生成内容自动翻页,兼容各种浏览器(已测试)----神器版!
转--http://www.2cto.com/kf/201402/277535.html 万能js实现翻页,动态生成内容自动翻页,兼容各种浏览器(已测试)----神器版! 2014-02-11 ...
- C# 翻页设计:首页,上一页,下一页,末页 ,跳转
int pageSize = 0; //每页显示行数 int nMax = 0; //总记录数 int pageCount = 0; //页数=总记录数/每页显示行数 int pageCurrent ...
- React + Node 单页应用「二」OAuth 2.0 授权认证 & GitHub 授权实践
关于项目 项目地址 预览地址 记录最近做的一个 demo,前端使用 React,用 React Router 实现前端路由,Koa 2 搭建 API Server, 最后通过 Nginx 做请求转发. ...
随机推荐
- Linux 文本对比 diff 命令详解(整理)
diff 命令详解 1.概述 windows系统下面就有不错的文本对比工具可以使用,例如常用的Beyond Compare,WinMerge都是图形界面的比较工具而且使用非常方便,如果你仅仅是在win ...
- EXTJS4.0 显示图片 动态图片
在网上找了好久没有好的解决方法 都是用 'box' 什么的组件 改写的 autoEl 好麻烦,修改 好的属性都不能用.弄了好久没弄成 最后: 用panel 显示 html 文本 追加 ‘'<i ...
- RabbitMQ-Java客户端API指南-下
RabbitMQ-Java客户端API指南-下 使用主机列表 可以将Address数组传递给newConnection().的地址是简单地在一个方便的类com.rabbitmq.client包与主机 ...
- P2135 方块消除
题目描述 Jimmy最近迷上了一款叫做方块消除的游戏.游戏规则如下:n个带颜色方格排成一列,相同颜色的方块连成一个区域(如果两个相邻方块颜色相同,则这两个方块属于同一区域).为简化题目,将连起来的同一 ...
- 湘潭邀请赛 2018 E From Tree to Graph
题意: 给出一棵树以及m,a,b,x0,y0.之后加m条边{(x1,LCA(x1,y1)),(x2,LCA(x2,y2))...(xm,LCA(xm,ym))}.定义z = f(0)^f(1)^... ...
- [BZOJ4205][FJ2015集训] 卡牌配对 [建图+最大流]
题面 这是bzoj权限题,题面可以去下面的离线题库找 离线4205,只有题面,不能提交 思路 二分图匹配 这道题模型显然就是个二分图匹配嘛 那我们两两判断一下然后连边匹配.....就只有30分了 因为 ...
- 开源作品ThinkJDBC—一行代码搞定数据库操作
1 简介 ThinkJD,又名ThinkJDBC,一个简洁而强大的开源JDBC操作库.你可以使用Java像ThinkPHP框架的M方法一样,一行代码搞定数据库操作.ThinkJD会自动管理数据库连接, ...
- POJ 3243 Clever Y | BSGS算法完全版
题目: 给你A,B,K 求最小的x满足Ax=B (mod K) 题解: 如果A,C互质请参考上一篇博客 将 Ax≡B(mod C) 看作是Ax+Cy=B方便叙述与处理. 我们将方程一直除去A,C的最大 ...
- BZOJ4888 [Tjoi2017]异或和 【树状数组】
题目链接 BZOJ4888 题解 要求所有连续异或和,转化为任意两个前缀和相减 要求最后的异或和,转化为求每一位\(1\)的出现次数 所以我们只需要对每一个\(i\)快速求出\(sum[i] - su ...
- NOIP2017赛前模拟11月6日—7日总结
收获颇丰的两天··· 题目1:序列操作 给定n个非负整数,进行m次操作,每次操作给出c,要求找出c个正整数数并将它们减去1,问最多能进行多少操作?n,m<=1000000 首先暴力贪心肯定是每次 ...