使用NodeJS开发前端打包程序

简介: 使用NodeJS开发前端打包程序

   每种语言都有自己的优势,互相结合各取所长使程序执行起来效率更高或者哪种实现方式较简单就用哪个,NodeJS是利用子进程来调用系统命令或者文件,文档见http://nodejs.org/api/child_process.html ,NodeJS子进程提供了与系统交互的重要接口,其主要API有: 标准输入、标准输出及标准错误输出的接口。

NodeJS 子进程提供了与系统交互的重要接口,其主要 API 有:

标准输入、标准输出及标准错误输出的接口

child.stdin 获取标准输入

child.stdout 获取标准输出

child.stderr 获取标准错误输出

获取子进程的PID:child.pid

提供生成子进程的方法:child_process.spawn(cmd, args=[], [options])

提供直接执行系统命令的方法:child_process.exec(cmd, [options], callback)

提供调用脚本文件的方法:child_process.execFile(file, [args], [options], [callback])

提供杀死进程的方法:child.kill(signal='SIGTERM'

1、利用子进程调用系统命令(获取系统内存使用情况)

   新建nodejs文件,名为cmd_memory.js,代码如下:


var spawn = require('child_process').spawn;

free = spawn('free', ['-m']);


// 捕获标准输出并将其打印到控制台 free.stdout.on('data', function(data) { console.log('standard output:\n' + data);

});


// 捕获标准错误输出并将其打印到控制台 free.stderr.on('data', function(data) { console.log('standard error output:\n' + data);

});


// 注册子进程关闭事件 free.on('exit', function(code, signal) { console.log('child process eixt ,exit:' + code);

});

注意:运行该脚本和直接运行命令'free -m'的结果是一样的

2、利用NodeJS开发前端打包程序

       我们在做前端开发的时候经常会在部署上线的时候做程序的打包和合并,我们接下来就会对如何使用 node.js 开发前端打包程序做非常深入的讲解,希望能够帮到有需要的同学。

我们现在做前端开发更多的是多人共同协作开发,每个人负责不同的模块,便于开发和调试。这样就导致我们最后部署上线的时候需要把所有人开发的模块进行合并,生成单个或多个文件上线。如果手动合并的话肯定是费时又费力,而且非常容易出错,所以我们一般都是通过一些工具来实现自动合并的功能。

打包程序的原理非常简单,入口文件->寻找依赖关系->替换依赖关系->生成文件,其中中间的两个步骤是递归执行的。

我们先来看一下使用 node.js 如何完成一个简单的文件合并功能:

 

01// 打包文件内容
02 var contentList = [];
03 // 排重列表
04 var loadedFileList = {};
05
06 // 打包主程序
07 function combine(filePath){
08 // 这里获取入口文件的内容
09 var fileContent = fs.readFileSync(filePath);
10 // 遍历文件内容
11 fileContent.forEach(function(value){
12 // 这里的findImport是需要你来实现的方法,用正则来匹配依赖关系
13 var matchFile = findImport(value);
14 if(matchFile){
15 //如果匹配到依赖关系
16 If(!loadedFileList[matchFile]){
17 //如果依赖关系不在排重列表中,递归调用combine
18 combine(matchFile);
19 contentList.push(‘n’);
20 }
21 }else{
22 contentList.push(value);
23 }
24 });
25 }

       最后只要根据 contentList 里面的内容来生成文件就可以了,怎么样,是不是很简单呢?下面我们就要介绍另外一种方式,使用流来完成我们的打包程序。

在 node.js 中,流(Stream)是一个由不同对象实现的抽象接口。流可以是可读的、可写的、或者既可读又可写的。所有的流都是 EventEmitter 的实例。我们可以通过继承接口来构造我们自己所需要的流。在我们的打包程序里面需要两个流,一个负责按行输出文件内容,另外一个负责处理依赖关系。所有的文件内容都在这两个流里面循环流动,当所有的依赖关系都处理完毕之后就结束流动并生成对应的文件,这样就达到我们的目的了。

让我们先来看一下负责按行输出文件内容的流是怎么样的:

 

01 var Stream = require('stream').Stream,
02 util = require('util'),
03 path = require('path'),
04 fs = require('fs');
05
06 // 构造函数
07 function LineStream() {
08 this.writable = true;
09 this.readable = true;
10 this.buffer = '';
11 }
12
13 module.exports = LineStream;
14 // 继承流接口
15 util.inherits(LineStream, Stream);
16
17 // 重写write方法,所有pipe过来的数据都会调用此方法
18 LineStream.prototype.write = function(data, encoding) {
19 var that = this;
20 // 把buffer转换为string类型
21 if (Buffer.isBuffer(data)) {
22 data = data.toString(encoding || 'utf8');
23 }
24
25 var parts = data.split(/n/g);
26
27 // 如果有上一次的buffer存在就添加到最前面
28 if (this.buffer.length > 0) {
29 parts[0] = this.buffer + parts[0];
30 }
31
32 // 遍历并发送数据
33 for (var i = 0; i < parts.length - 1; i++) {
34 this.emit('data', parts[i]);
35 }
36 // 把最后一行数据保存到buffer,使传递过来的数据保持连续和完整。
37 this.buffer = parts[parts.length - 1];
38 };
39 // end方法,在流结束时调用
40 LineStream.prototype.end = function() {
41 // 如果还有buffer,发送出去
42 if(this.buffer.length > 0){
43 this.emit('data',this.buffer);
44 this.buffer = '';
45 }
46 this.emit('end');
47 };

       这样我们的 lineStream 就完成了,我们看到在 write 方法里面就做了一件事,分解传递过来的数据并按行发送出去,然后我们看下处理依赖关系的流 DepsStream。

 

01 var stream = require('stream').Stream;
02 var util = require('util');
03 var fs = require('fs');
04 var path = require('path');
05
06 module.exports = DepsStream;
07 util.inherits(DepsStream,stream);
08
09 function DepsStream(){
10 this.writable = true;
11 this.readable = true;
12 this.buffer = '';
13 this.depsList = [];
14 };
15
16 // 这里的write方法只发送数据,不对数据做任何的处理
17 DepsStream.prototype.write = function(data){
18 this.emit('data',data);
19 };
20
21 // 我们在这里重新pipe方法,使其能够处理依赖关系和生成最终文件
22 DepsStream.prototype.pipe = function(dest,opt){
23 var that = this;
24 function ondata(chunk){
25 var matches = findImport(chunk);
26 if(matches){
27 if(this.depsList.indexOf(matches) >= 0){
28 // 我们在这里把处理过后的数据pipe回lineStream
29 dest.write('n');
30 }else{
31 this.depsList.push(matches);
32 var code = getFileContent(matches);
33 // 我们在这里把处理过后的数据pipe回lineStream
34 dest.write('n' + code);
35 }
36 }else{
37 this.buffer += chunk + 'n';
38 }
39 }
40 function onend(){
41 // 生成最终文件
42 var code = this.buffer;
43 fs.writeFileSync(filePublishUrl,code);
44 console.log(filePublishUrl + ' combine done.');
45 }
46 // 监听end事件
47 that.on('end',onend);
48 // 监听data事件
49 that.on('data',ondata);
50 };
51
52 // end方法
53 DepsStream.prototype.end = function(){
54 this.emit('end');
55 };

      我们看到上面的程序里面我们在 pipe 方法里面监听了 end 事件和 data 事件,ondata 方法主要用来对数据进行处理,发现有依赖关系的话就获取对应依赖关系的文件并重新发回给 LineStream 进行处理。onend 方法用来生成最终的文件,我们来看一下最终的调用方法:

 

1 var fileStream = fs.createReadStream(filepath);
2 var lineStream = new LineStream();
3 var depsStream = new DepsStream();
4
5 fileStream.pipe(lineStream);
6 lineStream.pipe(depsStream);
7 depsStream.pipe(lineStream);


目录
相关文章
|
23天前
|
JavaScript 前端开发 Docker
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
在使用 Deno 构建项目时,生成的可执行文件体积较大,通常接近 100 MB,而 Node.js 构建的项目体积则要小得多。这是由于 Deno 包含了完整的 V8 引擎和运行时,使其能够在目标设备上独立运行,无需额外安装依赖。尽管体积较大,但 Deno 提供了更好的安全性和部署便利性。通过裁剪功能、使用压缩工具等方法,可以优化可执行文件的体积。
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
|
6天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第36天】本文将引导您探索Node.js的世界,通过实际案例揭示其背后的原理和实践方法。从基础的安装到高级的异步处理,我们将一起构建一个简单的后端服务,并讨论如何优化性能。无论您是新手还是有经验的开发者,这篇文章都将为您提供新的视角和深入的理解。
|
11天前
|
Web App开发 存储 JavaScript
深入浅出Node.js后端开发
【10月更文挑战第31天】本文将引导你进入Node.js的奇妙世界,探索其如何革新后端开发。通过浅显易懂的语言和实际代码示例,我们将一起学习Node.js的核心概念、搭建开发环境,以及实现一个简单但完整的Web应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇通往高效后端开发的大门。
|
12天前
|
前端开发 JavaScript 安全
揭秘!前端大牛们如何高效解决跨域问题,提升开发效率!
【10月更文挑战第30天】在Web开发中,跨域问题是一大挑战。本文介绍前端大牛们常用的跨域解决方案,包括JSONP、CORS、postMessage和Nginx/Node.js代理,对比它们的优缺点,帮助初学者提升开发效率。
35 4
|
12天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
【10月更文挑战第30天】本文将通过一个Node.js的简单示例,引导你进入Node.js的世界。我们将从基础概念讲起,然后一步步深入到代码实现,最后总结Node.js在后端开发中的优势和应用场景。无论你是前端开发者还是后端新手,这篇文章都将为你打开一扇了解Node.js的大门。
25 2
|
25天前
|
SQL JavaScript 关系型数据库
node博客小项目:接口开发、连接mysql数据库
【10月更文挑战第14天】node博客小项目:接口开发、连接mysql数据库
|
9天前
|
Web App开发 JavaScript 前端开发
探索后端开发:Node.js与Express的完美结合
【10月更文挑战第33天】本文将带领读者深入了解Node.js和Express的强强联手,通过实际案例揭示它们如何简化后端开发流程,提升应用性能。我们将一起探索这两个技术的核心概念、优势以及它们如何共同作用于现代Web开发中。准备好,让我们一起开启这场技术之旅!
23 0
|
16天前
|
JavaScript 前端开发 安全
深入浅出Node.js后端开发
【10月更文挑战第26天】在这篇文章中,我们将一起探索Node.js的奇妙世界。不同于传统的Java或Python,Node.js以其异步非阻塞I/O和事件驱动的特性,在后端开发领域独树一帜。无论你是初学者还是资深开发者,这篇文章都将为你提供新的视角和思考。从基础概念到实际应用,我们一步步深入Node.js的世界,让你了解其不仅仅是JavaScript运行环境那么简单。
|
29天前
|
JSON 前端开发 JavaScript
前端模块打包器的深度解析
【10月更文挑战第13天】前端模块打包器的深度解析
|
30天前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
127 2