我们在做前端开发的时候经常会在部署上线的时候做程序的打包和合并,我们接下来就会对如何使用 node.js 开发前端打包程序做非常深入的讲解,希望能够帮到有需要的同学。
我们现在做前端开发更多的是多人共同协作开发,每个人负责不同的模块,便于开发和调试。这样就导致我们最后部署上线的时候需要把所有人开发的模块进行合并,生成单个或多个文件上线。如果手动合并的话肯定是费时又费力,而且非常容易出错,所以我们一般都是通过一些工具来实现自动合并的功能。
打包程序的原理非常简单,入口文件->寻找依赖关系->替换依赖关系->生成文件,其中中间的两个步骤是递归执行的。
我们先来看一下使用 node.js 如何完成一个简单的文件合并功能:
- // 打包文件内容
- var contentList = [];
- // 排重列表
- var loadedFileList = {};
-
- // 打包主程序
- function combine(filePath){
- // 这里获取入口文件的内容
- var fileContent = fs.readFileSync(filePath);
- // 遍历文件内容
- fileContent.forEach(function(value){
- // 这里的findImport是需要你来实现的方法,用正则来匹配依赖关系
- var matchFile = findImport(value);
-
if(matchFile){
- //如果匹配到依赖关系
- If(!loadedFileList[matchFile]){
- //如果依赖关系不在排重列表中,递归调用combine
- combine(matchFile);
- contentList.push(‘\n’);
- }
-
}else{
- contentList.push(value);
- }
- });
- }
最后只要根据 contentList 里面的内容来生成文件就可以了,怎么样,是不是很简单呢?下面我们就要介绍另外一种方式,使用流来完成我们的打包程序。
在 node.js 中,流(Stream)是一个由不同对象实现的抽象接口。流可以是可读的、可写的、或者既可读又可写的。所有的流都是 EventEmitter 的实例。我们可以通过继承接口来构造我们自己所需要的流。在我们的打包程序里面需要两个流,一个负责按行输出文件内容,另外一个负责处理依赖关系。所有的文件内容都在这两个流里面循环流动,当所有的依赖关系都处理完毕之后就结束流动并生成对应的文件,这样就达到我们的目的了。
让我们先来看一下负责按行输出文件内容的流是怎么样的:
- var Stream = require('stream').Stream,
-
util = require('util'),
-
path = require('path'),
-
fs = require('fs');
-
- // 构造函数
- function LineStream() {
- this.writable = true;
- this.readable = true;
-
this.buffer = '';
- }
-
- module.exports = LineStream;
- // 继承流接口
- util.inherits(LineStream, Stream);
-
- // 重写write方法,所有pipe过来的数据都会调用此方法
- LineStream.prototype.write = function(data, encoding) {
- var that = this;
- // 把buffer转换为string类型
-
if (Buffer.isBuffer(data)) {
-
data = data.toString(encoding || 'utf8');
- }
-
- var parts = data.split(/\n/g);
-
- // 如果有上一次的buffer存在就添加到最前面
-
if (this.buffer.length > 0) {
-
parts[0] = this.buffer + parts[0];
- }
-
- // 遍历并发送数据
-
for (var i = 0; i < parts.length - 1; i++) {
-
this.emit('data', parts[i]);
- }
- // 把最后一行数据保存到buffer,使传递过来的数据保持连续和完整。
-
this.buffer = parts[parts.length - 1];
- };
- // end方法,在流结束时调用
- LineStream.prototype.end = function() {
- // 如果还有buffer,发送出去
-
if(this.buffer.length > 0){
-
this.emit('data',this.buffer);
-
this.buffer = '';
- }
-
this.emit('end');
- };
这样我们的 lineStream 就完成了,我们看到在 write 方法里面就做了一件事,分解传递过来的数据并按行发送出去,然后我们看下处理依赖关系的流 DepsStream。
- var stream = require('stream').Stream;
-
var util = require('util');
-
var fs = require('fs');
-
var path = require('path');
-
- module.exports = DepsStream;
- util.inherits(DepsStream,stream);
-
- function DepsStream(){
- this.writable = true;
- this.readable = true;
-
this.buffer = '';
- this.depsList = [];
- };
-
- // 这里的write方法只发送数据,不对数据做任何的处理
- DepsStream.prototype.write = function(data){
-
this.emit('data',data);
- };
-
- // 我们在这里重新pipe方法,使其能够处理依赖关系和生成最终文件
- DepsStream.prototype.pipe = function(dest,opt){
- var that = this;
- function ondata(chunk){
- var matches = findImport(chunk);
-
if(matches){
-
if(this.depsList.indexOf(matches) >= 0){
- // 我们在这里把处理过后的数据pipe回lineStream
-
dest.write('\n');
-
}else{
- this.depsList.push(matches);
- var code = getFileContent(matches);
- // 我们在这里把处理过后的数据pipe回lineStream
-
dest.write('\n' + code);
- }
-
}else{
-
this.buffer += chunk + '\n';
- }
- }
- function onend(){
- // 生成最终文件
- var code = this.buffer;
- fs.writeFileSync(filePublishUrl,code);
-
console.log(filePublishUrl + ' combine done.');
- }
- // 监听end事件
-
that.on('end',onend);
- // 监听data事件
-
that.on('data',ondata);
- };
-
- // end方法
- DepsStream.prototype.end = function(){
-
this.emit('end');
- };
我们看到上面的程序里面我们在 pipe 方法里面监听了 end 事件和 data 事件,ondata 方法主要用来对数据进行处理,发现有依赖关系的话就获取对应依赖关系的文件并重新发回给 LineStream 进行处理。onend 方法用来生成最终的文件,我们来看一下最终的调用方法:
- var fileStream = fs.createReadStream(filepath);
-
var lineStream = new LineStream();
-
var depsStream = new DepsStream();
-
- fileStream.pipe(lineStream);
- lineStream.pipe(depsStream);
- depsStream.pipe(lineStream);
怎么样,是不是非常简单,感兴趣的同学赶快尝试一下吧。
分享到:
相关推荐
node.js前端部署和打包插件grunt-bbb,如果你使用了require.js那你选择他作为前端部署工具就对了,示例:https://github.com/backbone-boilerplate/grunt-bbb,解压到C:\Users\Administrator\AppData\Roaming\npm\ ...
基于浏览器的完全打包环境,没有 Nodejs 也照样打包前端项目.zip
这使用一个简单的计算器应用程序来演示使用 Node.JS 开发前端代码的一些实践。 表明: 使用 Gulp 的基本构建文件 使用 Jasmine 在 Node 中测试 Javascript 代码 使用 Browserify 打包前端模块 编写自定义 Gulp ...
Brunch - 前端web应用程序构建工具使用简单的声明性配置,快速增量编译,和一个固执己见的工作流
gulp打包js,min.js,d.ts等
对JavaScript和node.js研究并实现WEB聊天系统
随着前端体积越来越大,功能越来越丰富,这时候就需要将前端工程化,而webpack就是用于将前端各种文件打包起来。一个简单的webpack应该包含以下几个概念 入口起点 输出 配置 组件 加载器 插件 模块 模块热...
基于Node.js的医药搜索平台网站设计与实现
基于html和node.js实现的网页音乐播放器
更方便的把前端打包好的代码传到服务端开发机上进行联调
Lc Framework(LcF自用web开发框架)站在巨人的肩膀上简单介绍此项目是基于Node.js(全栈js,es6),Web服务使用express进行搭建,使用gRPC进行前后端服务通信,整合前端打包工具webpack(可替换gulp).小可构建一个...
Webpack是前端的一个项目构建工具 基于Node.js开发 因此 若要使用webpack 必须先安装Node.js 借助Webpack这个前端自动化构建工具 可以完美实现资源的合并 打包 压缩 混淆等诸多功能 示意图: 官网:...
Liblog是一个简单易用的Markdown博客系统,它是基于开源框架thinkJS(使用 ES6/7 特性开发 Node.js 框架)开发的nodejs项目 需要mysql数据库支持,具有管理后台功能,更新博客分为普通文章和markdown文章,markdown...
在使用node.js下载打包工具webpack依赖,配置运行.eslintrc.js文件报出es加载模块错误, 因为node.js版本低导致升级node.js至最新版
实现require.js+r.js在node环境下合并,打包,压缩JS代码
5.在books文件夹下执行npm run build打包前端文件,打包完成后将该目录新增的dist文件夹复制到node文件夹中  6.打包完成后将dist文件夹复制到node文件夹下  7.将node文件夹下baseURL.js文件中的ip地址,...
geotiff.js 从各种不同的(Geo)TIFF文件类型中读取(地理空间)元数据和原始数组数据。 特征 当前可用的功能: 解析来自各种来源的TIFF: 远程(通过fetch或XHR) 从本地ArrayBuffer 从文件系统(在使用...
前后端分离,本地前端开发调用接口会有跨域问题,一般有以下3种解决方法: 1. 后端接口打包到本地运行(缺点:每次后端更新都要去测试服下一个更新包,还要在本地搭建java运行环境,麻烦) 2. CORS跨域:后端接口...
前端以SPA单页形式,后端以nodejs为主,提供api接口。前端页面使用angular2,管理后台使用vue2,使用爬虫来简单抓取简书页面的一些数据,(人懒没办法)
很多前端开发者都使用过 webpack,通过 webpack 开发 JavaScript 项目可以带来很多好处 支持通过 yarn 或 npm 引入和使用 node_modules 模块 支持丰富且灵活的 loaders 和 plugins 支持 alias 还有很多... 为什么...