使用Node.js写一个代码生成器的方法步骤

 背景

第一次接触代码生成器用的是动软代码生成器,数据库设计好之后,一键生成后端 curd代码。之后也用过 CodeSmith , T4。目前市面上也有很多优秀的代码生成器,而且大部分都提供可视化界面操作。

自己写一个的原因是因为要集成到自己写的一个小工具中,而且使用 Node.js 这种动态脚本语言进行编写更加灵活。

原理

代码生成器的原理就是: 数据 + 模板 => 文件 。

数据 一般为数据库的表字段结构。

模板 的语法与使用的模板引擎有关。

使用模板引擎将 数据 和 模板 进行编译,编译后的内容输出到文件中就得到了一份代码文件。

功能

因为这个代码生成器是要集成到一个小工具lazy-mock内,这个工具的主要功能是启动一个 mock server 服务,包含curd功能,并且支持数据的持久化,文件变化的时候自动重启服务以最新的代码提供 api mock 服务。

代码生成器的功能就是根据配置的数据和模板,编译后将内容输出到指定的目录文件中。因为添加了新的文件,mock server 服务会自动重启。

还要支持模板的定制与开发,以及使用 CLI 安装模板。

可以开发前端项目的模板,直接将编译后的内容输出到前端项目的相关目录下,webpack 的热更新功能也会起作用。

模板引擎

模板引擎使用的是nunjucks

lazy-mock使用的构建工具是 gulp,使用 gulp-nodemon 实现 mock-server 服务的自动重启。所以这里使用 gulp-nunjucks-render 配合 gulp 的构建流程。

代码生成

编写一个 gulp task :

const rename = require('gulp-rename')
const nunjucksRender = require('gulp-nunjucks-render')
const codeGenerate = require('./templates/generate')
const ServerFullPath = require('./package.json').ServerFullPath; //mock -server项目的绝对路径
const FrontendFullPath = require('./package.json').FrontendFullPath; //前端项目的绝对路径
const nunjucksRenderConfig = {
 path: 'templates/server',
 envOptions: {
  tags: {
   blockStart: '<%',
   blockEnd: '%>',
   variableStart: '<$',
   variableEnd: '$>',
   commentStart: '<#',
   commentEnd: '#>'
  },
 },
 ext: '.js',
 //以上是 nunjucks 的配置
 ServerFullPath,
 FrontendFullPath
}
gulp.task('code', function () {
 require('events').EventEmitter.defaultMaxListeners = 0
 return codeGenerate(gulp, nunjucksRender, rename, nunjucksRenderConfig)
});

代码具体结构细节可以打开lazy-mock进行参照

为了支持模板的开发,以及更灵活的配置,我将代码生成的逻辑全都放在模板目录中。

templates 是存放模板以及数据配置的目录。结构如下:

只生成 lazy-mock 代码的模板中 :

generate.js 的内容如下:

const path = require('path')
const CodeGenerateConfig = require('./config').default;
const Model = CodeGenerateConfig.model;

module.exports = function generate(gulp, nunjucksRender, rename, nunjucksRenderConfig) {
  nunjucksRenderConfig.data = {
    model: CodeGenerateConfig.model,
    config: CodeGenerateConfig.config
  }
  const ServerProjectRootPath = nunjucksRenderConfig.ServerFullPath;
  //server
  const serverTemplatePath = 'templates/server/'
  gulp.src(`${serverTemplatePath}controller.njk`)
    .pipe(nunjucksRender(nunjucksRenderConfig))
    .pipe(rename(Model.name + '.js'))
    .pipe(gulp.dest(ServerProjectRootPath + CodeGenerateConfig.config.ControllerRelativePath));

  gulp.src(`${serverTemplatePath}service.njk`)
    .pipe(nunjucksRender(nunjucksRenderConfig))
    .pipe(rename(Model.name + 'Service.js'))
    .pipe(gulp.dest(ServerProjectRootPath + CodeGenerateConfig.config.ServiceRelativePath));

  gulp.src(`${serverTemplatePath}model.njk`)
    .pipe(nunjucksRender(nunjucksRenderConfig))
    .pipe(rename(Model.name + 'Model.js'))
    .pipe(gulp.dest(ServerProjectRootPath + CodeGenerateConfig.config.ModelRelativePath));

  gulp.src(`${serverTemplatePath}db.njk`)
    .pipe(nunjucksRender(nunjucksRenderConfig))
    .pipe(rename(Model.name + '_db.json'))
    .pipe(gulp.dest(ServerProjectRootPath + CodeGenerateConfig.config.DBRelativePath));

  return gulp.src(`${serverTemplatePath}route.njk`)
    .pipe(nunjucksRender(nunjucksRenderConfig))
    .pipe(rename(Model.name + 'Route.js'))
    .pipe(gulp.dest(ServerProjectRootPath + CodeGenerateConfig.config.RouteRelativePath));
}

类似:

gulp.src(`${serverTemplatePath}controller.njk`)
    .pipe(nunjucksRender(nunjucksRenderConfig))
    .pipe(rename(Model.name + '.js'))
    .pipe(gulp.dest(ServerProjectRootPath + CodeGenerateConfig.config.ControllerRelativePath));

表示使用 controller.njk 作为模板,nunjucksRenderConfig作为数据(模板内可以获取到 nunjucksRenderConfig 属性 data 上的数据)。编译后进行文件重命名,并保存到指定目录下。

model.js 的内容如下:

var shortid = require('shortid')
var Mock = require('mockjs')
var Random = Mock.Random

//必须包含字段id
export default {
  name: "book",
  Name: "Book",
  properties: [
    {
      key: "id",
      title: "id"
    },
    {
      key: "name",
      title: "书名"
    },
    {
      key: "author",
      title: "作者"
    },
    {
      key: "press",
      title: "出版社"
    }
  ],
  buildMockData: function () {//不需要生成设为false
    let data = []
    for (let i = 0; i < 100; i++) {
      data.push({
        id: shortid.generate(),
        name: Random.cword(5, 7),
        author: Random.cname(),
        press: Random.cword(5, 7)
      })
    }
    return data
  }
}

模板中使用最多的就是这个数据,也是生成新代码需要配置的地方,比如这里配置的是 book ,生成的就是关于 book 的curd 的 mock 服务。要生成别的,修改后执行生成命令即可。

buildMockData 函数的作用是生成 mock 服务需要的随机数据,在 db.njk 模板中会使用:

{
 "<$ model.name $>":<% if model.buildMockData %><$ model.buildMockData()|dump|safe $><% else %>[]<% endif %>
}

这也是 nunjucks 如何在模板中执行函数

config.js 的内容如下:

export default {
  //server
  RouteRelativePath: '/src/routes/',
  ControllerRelativePath: '/src/controllers/',
  ServiceRelativePath: '/src/services/',
  ModelRelativePath: '/src/models/',
  DBRelativePath: '/src/db/'
}

配置相应的模板编译后保存的位置。

config/index.js 的内容如下:

import model from './model';
import config from './config';
export default {
  model,
  config
}

针对 lazy-mock 的代码生成的功能就已经完成了,要实现模板的定制直接修改模板文件即可,比如要修改 mock server 服务 api 的接口定义,直接修改 route.njk 文件:

import KoaRouter from 'koa-router'
import controllers from '../controllers/index.js'
import PermissionCheck from '../middleware/PermissionCheck'

const router = new KoaRouter()
router
  .get('/<$ model.name $>/paged', controllers.<$model.name $>.get<$ model.Name $>PagedList)
  .get('/<$ model.name $>/:id', controllers.<$ model.name $>.get<$ model.Name $>)
  .del('/<$ model.name $>/del', controllers.<$ model.name $>.del<$ model.Name $>)
  .del('/<$ model.name $>/batchdel', controllers.<$ model.name $>.del<$ model.Name $>s)
  .post('/<$ model.name $>/save', controllers.<$ model.name $>.save<$ model.Name $>)

module.exports = router

模板开发与安装

不同的项目,代码结构是不一样的,每次直接修改模板文件会很麻烦。

需要提供这样的功能:针对不同的项目开发一套独立的模板,支持模板的安装。

代码生成的相关逻辑都在模板目录的文件中,模板开发没有什么规则限制,只要保证目录名为 templates , generate.js 中导出 generate 函数即可。

模板的安装原理就是将模板目录中的文件全部覆盖掉即可。不过具体的安装分为本地安装与在线安装。

之前已经说了,这个代码生成器是集成在 lazy-mock中的,我的做法是在初始化一个新 lazy-mock 项目的时候,指定使用相应的模板进行初始化,也就是安装相应的模板。

使用 Node.js 写了一个 CLI 工具 lazy-mock-cli,已发到 npm ,其功能包含下载指定的远程模板来初始化新的 lazy-mock 项目。代码参考( copy )了vue-cli2。代码不难,说下某些关键点。

安装 CLI 工具:

npm install lazy-mock -g

使用模板初始化项目:

lazy-mock init d2-admin-pm my-project

d2-admin-pm是我为一个 前端项目已经写好的一个模板。

init 命令调用的是 lazy-mock-init.js 中的逻辑:

#!/usr/bin/env node
const download = require('download-git-repo')
const program = require('commander')
const ora = require('ora')
const exists = require('fs').existsSync
const rm = require('rimraf').sync
const path = require('path')
const chalk = require('chalk')
const inquirer = require('inquirer')
const home = require('user-home')
const fse = require('fs-extra')
const tildify = require('tildify')
const cliSpinners = require('cli-spinners');
const logger = require('../lib/logger')
const localPath = require('../lib/local-path')

const isLocalPath = localPath.isLocalPath
const getTemplatePath = localPath.getTemplatePath

program.usage('<template-name> [project-name]')
  .option('-c, --clone', 'use git clone')
  .option('--offline', 'use cached template')

program.on('--help', () => {
  console.log(' Examples:')
  console.log()
  console.log(chalk.gray('  # create a new project with an official template'))
  console.log('  $ lazy-mock init d2-admin-pm my-project')
  console.log()
  console.log(chalk.gray('  # create a new project straight from a github template'))
  console.log('  $ vue init username/repo my-project')
  console.log()
})

function help() {
  program.parse(process.argv)
  if (program.args.length < 1) return program.help()
}
help()
//模板
let template = program.args[0]
//判断是否使用官方模板
const hasSlash = template.indexOf('/') > -1
//项目名称
const rawName = program.args[1]
//在当前文件下创建
const inPlace = !rawName || rawName === '.'
//项目名称
const name = inPlace ? path.relative('../', process.cwd()) : rawName
//创建项目完整目标位置
const to = path.resolve(rawName || '.')
const clone = program.clone || false

//缓存位置
const serverTmp = path.join(home, '.lazy-mock', 'sever')
const tmp = path.join(home, '.lazy-mock', 'templates', template.replace(/[\/:]/g, '-'))
if (program.offline) {
  console.log(`> Use cached template at ${chalk.yellow(tildify(tmp))}`)
  template = tmp
}

//判断是否当前目录下初始化或者覆盖已有目录
if (inPlace || exists(to)) {
  inquirer.prompt([{
    type: 'confirm',
    message: inPlace
      ? 'Generate project in current directory?'
      : 'Target directory exists. Continue?',
    name: 'ok'
  }]).then(answers => {
    if (answers.ok) {
      run()
    }
  }).catch(logger.fatal)
} else {
  run()
}

function run() {
  //使用本地缓存
  if (isLocalPath(template)) {
    const templatePath = getTemplatePath(template)
    if (exists(templatePath)) {
      generate(name, templatePath, to, err => {
        if (err) logger.fatal(err)
        console.log()
        logger.success('Generated "%s"', name)
      })
    } else {
      logger.fatal('Local template "%s" not found.', template)
    }
  } else {
    if (!hasSlash) {
      //使用官方模板
      const officialTemplate = 'lazy-mock-templates/' + template
      downloadAndGenerate(officialTemplate)
    } else {
      downloadAndGenerate(template)
    }
  }
}

function downloadAndGenerate(template) {
  downloadServer(() => {
    downloadTemplate(template)
  })
}

function downloadServer(done) {
  const spinner = ora('downloading server')
  spinner.spinner = cliSpinners.bouncingBall
  spinner.start()
  if (exists(serverTmp)) rm(serverTmp)
  download('wjkang/lazy-mock', serverTmp, { clone }, err => {
    spinner.stop()
    if (err) logger.fatal('Failed to download server ' + template + ': ' + err.message.trim())
    done()
  })
}

function downloadTemplate(template) {
  const spinner = ora('downloading template')
  spinner.spinner = cliSpinners.bouncingBall
  spinner.start()
  if (exists(tmp)) rm(tmp)
  download(template, tmp, { clone }, err => {
    spinner.stop()
    if (err) logger.fatal('Failed to download template ' + template + ': ' + err.message.trim())
    generate(name, tmp, to, err => {
      if (err) logger.fatal(err)
      console.log()
      logger.success('Generated "%s"', name)
    })
  })
}

function generate(name, src, dest, done) {
  try {
    fse.removeSync(path.join(serverTmp, 'templates'))
    const packageObj = fse.readJsonSync(path.join(serverTmp, 'package.json'))
    packageObj.name = name
    packageObj.author = ""
    packageObj.description = ""
    packageObj.ServerFullPath = path.join(dest)
    packageObj.FrontendFullPath = path.join(dest, "front-page")
    fse.writeJsonSync(path.join(serverTmp, 'package.json'), packageObj, { spaces: 2 })
    fse.copySync(serverTmp, dest)
    fse.copySync(path.join(src, 'templates'), path.join(dest, 'templates'))
  } catch (err) {
    done(err)
    return
  }
  done()
}

判断了是使用本地缓存的模板还是拉取最新的模板,拉取线上模板时是从官方仓库拉取还是从别的仓库拉取。

一些小问题

目前代码生成的相关数据并不是来源于数据库,而是在 model.js 中简单配置的,原因是我认为一个 mock server 不需要数据库,lazy-mock 确实如此。

但是如果写一个正儿八经的代码生成器,那肯定是需要根据已经设计好的数据库表来生成代码的。那么就需要连接数据库,读取数据表的字段信息,比如字段名称,字段类型,字段描述等。而不同关系型数据库,读取表字段信息的 sql 是不一样的,所以还要写一堆balabala的判断。可以使用现成的工具 sequelize-auto, 把它读取的 model 数据转成我们需要的格式即可。

生成前端项目代码的时候,会遇到这种情况:

某个目录结构是这样的:

index.js 的内容:

import layoutHeaderAside from '@/layout/header-aside'
export default {
  "layoutHeaderAside": layoutHeaderAside,
  "menu": () => import(/* webpackChunkName: "menu" */'@/pages/sys/menu'),
  "route": () => import(/* webpackChunkName: "route" */'@/pages/sys/route'),
  "role": () => import(/* webpackChunkName: "role" */'@/pages/sys/role'),
  "user": () => import(/* webpackChunkName: "user" */'@/pages/sys/user'),
  "interface": () => import(/* webpackChunkName: "interface" */'@/pages/sys/interface')
}

如果添加一个 book 就需要在这里加上 "book": () => import(/* webpackChunkName: "book" */'@/pages/sys/book')

这一行内容也是可以通过配置模板来生成的,比如模板内容为:

"<$ model.name $>": () => import(/* webpackChunkName: "<$ model.name $>" */'@/pages<$ model.module $><$ model.name $>')

但是生成的内容怎么加到 index.js 中呢?

第一种方法:复制粘贴

第二种方法:

这部分的模板为 routerMapComponent.njk

export default {
  "<$ model.name $>": () => import(/* webpackChunkName: "<$ model.name $>" */'@/pages<$ model.module $><$ model.name $>')
}

编译后文件保存到 routerMapComponents 目录下,比如 book.js

修改 index.js :

const files = require.context('./', true, /\.js$/);
import layoutHeaderAside from '@/layout/header-aside'

let componentMaps = {
  "layoutHeaderAside": layoutHeaderAside,
  "menu": () => import(/* webpackChunkName: "menu" */'@/pages/sys/menu'),
  "route": () => import(/* webpackChunkName: "route" */'@/pages/sys/route'),
  "role": () => import(/* webpackChunkName: "role" */'@/pages/sys/role'),
  "user": () => import(/* webpackChunkName: "user" */'@/pages/sys/user'),
  "interface": () => import(/* webpackChunkName: "interface" */'@/pages/sys/interface'),
}
files.keys().forEach((key) => {
  if (key === './index.js') return
  Object.assign(componentMaps, files(key).default)
})
export default componentMaps

使用了 require.context

我目前也是使用了这种方法

第三种方法:

开发模板的时候,做特殊处理,读取原有 index.js 的内容,按行进行分割,在数组的最后一个元素之前插入新生成的内容,注意逗号的处理,将新数组内容重新写入 index.js 中,注意换行。

打个广告

如果你想要快速的创建一个 mock-server,同时还支持数据的持久化,又不需要安装数据库,还支持代码生成器的模板开发,欢迎试试lazy-mock

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java的MyBatis框架中MyBatis Generator代码生成器的用法

    关于Mybatis Generator MyBatis Generator (MBG) 是一个Mybatis的代码生成器 MyBatis 和 iBATIS. 他可以生成Mybatis各个版本的代码,和iBATIS 2.2.0版本以后的代码. 他可以内省数据库的表(或多个表)然后生成可以用来访问(多个)表的基础对象. 这样和数据库表进行交互时不需要创建对象和配置文件. MBG的解决了对数据库操作有最大影响的一些简单的CRUD(插入,查询,更新,删除)操作. 您仍然需要对联合查询和存储过程手写SQL

  • 代码生成器 document.write()

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD><TITLE>代码转换器</TITLE> <META http-equiv=Content-Type content="text/html; charset=gb2312"> <STYLE type=text/css>BODY {   

  • ext 代码生成器

    本文件为:ext_editgrid_products.js,用来显示,编辑,删除products表的数据. 复制代码 代码如下: var productsgrid; var productsstore; var productslimit = 25; //每页显示条数 var productsListPostUrl = "/management/procrequest/Proc_products.ashx?action=getlist"; var productsModifyPostU

  • js之弹出式窗口代码生成器

    弹出式窗口代码生成器 要完成此效果把如下代码加入到区域中 -1){ space=txt.indexOf(wrd); txt=txt.substring(0,space)+smut+txt.substring((space+wrdl),txt.length);} smut=">"; replacewords="> "; space=replacewords.indexOf(" "); wrd=replacewords.substring

  • javascript GUID生成器实现代码

    /jslib/other/IntUtil_post.js大家先把上面的代码保存到本地.保存为IntUtil_post.js测试代码: 复制代码 代码如下: <script language="javascript" src="IntUtil_post.js"></script> <script language="javascript"> <!-- alert($System.Math.IntUtil.g

  • C++随机点名生成器实例代码(老师们的福音!)

    用途: 随机点名 原理: 从exe文件同目录下的文档中导入人员信息(可以多重),通过rand+Hash实现,按空格键即可生成. C++中rand()函数可以用来产生随机数,但是是属于伪随机数. rand()函数用法: 在使用rand()函数的时候,首先需要包含头文件#include<stdlib.h> ,用法是int rand(void) ,产生的随机数范围是0~65536,类型为unsigned int,不能超过范围.rand()函数不接受参数,默认以1为种子(即起始值). 随机数生成器总是

  • Java实现简单字符生成器代码例子

    创建成功的字符串对象,其长度是固定的,内容是不能被修改和编辑.虽然使用"+"可以达到增加新字符或字符串的目的,但"+"会产生一个新的String实例,会在内存中创建新的字符串对象.如果重复地对字符串进行修改,将极大地增加系统开销.J2SE自5.0增加了可变的字符序列String-Builder类,大大地提高了频繁增加字符串的效率.下面看个简单的例子. public class Jerque { /** * 比较一般情况下的字符串生成器,和String-Builder

  • 基于Mybatis plus 自动代码生成器的实现代码

    1.使用的是maven项目,添加依赖 <!-- mybatis-plus begin --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>2.2.0</version> </dependency> 还有数据库的连接 <dependency> <

  • 使用Node.js写一个代码生成器的方法步骤

     背景 第一次接触代码生成器用的是动软代码生成器,数据库设计好之后,一键生成后端 curd代码.之后也用过 CodeSmith , T4.目前市面上也有很多优秀的代码生成器,而且大部分都提供可视化界面操作. 自己写一个的原因是因为要集成到自己写的一个小工具中,而且使用 Node.js 这种动态脚本语言进行编写更加灵活. 原理 代码生成器的原理就是: 数据 + 模板 => 文件 . 数据 一般为数据库的表字段结构. 模板 的语法与使用的模板引擎有关. 使用模板引擎将 数据 和 模板 进行编译,编译

  • 详解用Node.js写一个简单的命令行工具

    本文介绍了用Node.js写一个简单的命令行工具,分享给大家,具体如下: 操作系统需要为Linux 1. 目标 在命令行输入自己写的命令,完成目标任务 命令行要求全局有效 命令行要求可以删除 命令行作用,生成一个文件,显示当前的日期 2. 代码部分 新建一个文件,命名为sherryFile 文件sherryFile的内容 介绍: 生成一个文件,文件内容为当前日期和创建者 #! /usr/bin/env node console.log('command start'); const fs = r

  • 使用NODE.JS创建一个WEBSERVER(服务器)的步骤

    目录 什么是 nodejs 安装nodejs 如何使用node创建hello world? 如何使用nodejs读写文件 使用nodejs创建web服务器 如何根据不同的请求路径返回不同数据 将数据响应到前端 什么是 nodejs Node.js发布于2009年5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动.非阻塞式I/O模型, 让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP.Python.

  • 利用node.js写一个爬取知乎妹纸图的小爬虫

    前言 说起写node爬虫的原因,真是羞羞呀.一天,和往常一样,晚上吃过饭便刷起知乎来,首页便是推荐的你见过最漂亮的女生长什么样?,点进去各种漂亮的妹纸爆照啊!!!,看的我好想把这些好看的妹纸照片都存下来啊!一张张点击保存,就在第18张得时候,突然想起.我特么不是程序员么,这种手动草做的事,怎么能做,不行我不能丢程序员的脸了,于是便开始这次爬虫之旅. 原理 初入爬虫的坑,没有太多深奥的理论知识,要获取知乎上帖子中的一张图片,我把它归结为以下几步. 准备一个url(当然是诸如你见过最漂亮的女生长什么

  • 30分钟用Node.js构建一个API服务器的步骤详解

    Node.js 对初学者来说可能是令人望而却步的,其灵活的结构和缺乏严格的规范使它看起来很复杂. 本教程是 Node.js,Express 框架和 MongoDB 的快速指南,重点介绍基本的 REST 路由和基本的数据库交互.你将构建一个简单的 API 框架模版,然后可以将其用作任何应用. 本教程适用于:你应该对 REST API 和 CRUD 操作有基本的了解,还有基本的 JavaScript 知识.我用的是 ES6(主要是箭头函数),但并不是很复杂. 在本教程中,我们将为创建一个网络笔记应用

  • 用node.js写一个jenkins发版脚本

    背景 每次到网页里手动发版有点烦,写个脚本来提高开发效率. CFG 在 jenkins 设置里获取 API TOKEN. 把 host 和账号密码拼接起来就可以通过鉴权. const token = { user: '', password: '', } const host = 'jenkins.xxx.cn'; const basicUrl = `http://${token.user}:${token.password}@${host}`; BUILD 调用 jenkins 提供的 jen

  • Node.js创建一个Express服务的方法详解

    本文实例讲述了Node.js创建一个Express服务的方法.分享给大家供大家参考,具体如下: 1.创建一个HttpServer服务端 在node.js官网下载好node的Windows版本后一路下一步安装好了node,新建一个server.js文件,开始第一个node文件.首先在文件开头需要使用require包含所需要的模块,然后利用http.createServer创建一个server,并执行回调函数.在回调函数内对请求req进行处理,并返回res结果. 利用url的parse方法将req请

  • Node.js中流(stream)的使用方法示例

    前言 本文主要给大家介绍了关于Node.js 流(stream)的使用方法,分享出来供大家参考学习,下面话不多说,来一起看看详细的介绍: 流是基于事件的API,用于管理和处理数据,而且有不错的效率.借助事件和非阻塞I/O库,流模块允许在其可用的时候动态处理,在其不需要的时候释放掉. 使用流的好处 举一个读取文件的例子: 使用fs.readFileSync同步读取一个文件,程序会被阻塞,所有的数据都会被读取到内存中. 换用fs.readFile读取文件,程序不会被阻塞,但是所有的数据依旧会被一次性

  • Node.js静态服务器的实现方法

    当你输入一个url时,这个url可能对应服务器上的一个资源(文件)也可能对应一个目录. So服务器会对这个url进行分析,针对不同的情况做不同的事. 如果这个url对应的是一个文件,那么服务器就会返回这个文件. 如果这个url对应的是一个文件夹,那么服务器会返回这个文件夹下包含的所有子文件/子文件夹的列表. 以上,就是一个静态服务器所主要干的事. 但真实的情况不会像这么简单, 我们所拿到的url可能是错误的,它所对应的文件或则文件夹或许根本不存在, 又或则有些文件和文件夹是被系统保护起来的是隐藏

  • JavaScript+Node.js写一款markdown解析器

    目录 1. 准备工作 2. 处理图片&超链接 3. 处理blockquote 4. 处理标题 5. 处理字体 6. 处理代码块 7. 处理列表 8. 处理表格 9. 调用方法 1. 准备工作 首先编写getHtml函数,传入markdown文本字符串,这里使用fs读取markdown文件内容,返回值是转换过后的字符串. const fs = require('fs'); const source = fs.readFileSync('./test.md', 'utf-8'); const get

随机推荐