Quantcast
Channel: CNode:Node.js专业中文社区
Viewing all 14821 articles
Browse latest View live

egg-redis不支持await吗?

$
0
0
let aa = await this.app.redis.set(userId,token)

用await就跑不起来,去掉await打印出来是个peomise对象

Promise {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined,
  _trace:
   { Error
    at Promise.longStackTracesCaptureStackTrace [as _captureStackTrace] (c:\Users\qiao\Desktop\git\egg-club\node_modules\.3.5.1@bluebird\js\release\debuggability.js:400:19)
    at Promise._resolveFromExecutor (c:\Users\qiao\Desktop\git\egg-club\node_modules\.3.5.1@bluebird\js\release\promise.js:480:10)
    at new Promise (c:\Users\qiao\Desktop\git\egg-club\node_modules\.3.5.1@bluebird\js\release\promise.js:79:10)
    at Command.initPromise (c:\Users\qiao\Desktop\git\egg-club\node_modules\.2.5.0@ioredis\lib\command.js:63:18)
    at new Command (c:\Users\qiao\Desktop\git\egg-club\node_modules\.2.5.0@ioredis\lib\command.js:51:8)
    at Redis.get (c:\Users\qiao\Desktop\git\egg-club\node_modules\.2.5.0@ioredis\lib\commander.js:131:29)
    at service.users.compare.then.res (c:\Users\qiao\Desktop\git\egg-club\app\service\session.js:21:41)
    at <anonymous>
     _parent: undefined,
     _promisesCreated: 0,
     _length: 1,
     _promiseCreated: null } }
	 ```

问一下哈,node中有什么值得加入的微信群么,或者在上海有没有一些线下活动?

$
0
0

写node好长时间啦,感觉一直没找到大部队, 立此贴,寻找大部队。

最简單直接的 Koa2 的脚手架发布1.0

$
0
0

Github:https://github.com/chungchi300/koa2-safe-start如果你有兴趣,请给我一颗星星

最简單直接的 Koa2 的脚手架

哲学

我不想知道你的哲学,但我想立即开始并完成工作

  • 迅速开发 - 自动热重启服务 + 测试驱动开发模式 + 重置数据库(by cli)
  • 生产就绪 - 有node 和 npm 馬上可以部署,不用安裝任何东西
  • 從眾 - 80%人会做的设计决定(design decision)和80%人会使用的库(library)
  • 结构简單 - routes + MVC + 中间件(Middleware)
  • 没有魔法 - 可由app.js 開始 , 25 分钟读懂的代码

特别之处

  1. 没有babel配置(Node 9)
  2. Nodemon 自动热重启服务
  3. 自帶会员系统 (可拆开)(Passport js)
  4. 邮件服务 (Sparkpost)
  5. 对象关系映射(ORM) (Sequelize)
  6. 多个配置(/.env production.json,test.json,development.json)
  7. koa-router

技术堆栈

  1. Node js
  2. koa2
  3. Sequelize
  4. Mysql/SQlite

安装并运行

1. git clone git@github.com:chungchi300/koa2-safe-start.git
//更改 database
2. src/config/default.js  (default sqlite but suggest mysql in production)
3. npm i && npm run reset && npm start

访问

测试服务器

开发模式

文件修改后nodemon立即自动重启 Node.js 服务

npm run start

在优酷上观看

测试驱动开发模式

文件修改后Jest立即自动重新运行所有测试

npm run test

在优酷上观看

线上模式

使用pm2是node进程管理器,如果node进程崩溃立即自动重启进程

npm run production

在优酷上观看

配置&&部署线上

默认配置文件位于 src/config/default.js.

.env 配置会覆盖(override) 默认配置.

e.g

.env/production.json 覆盖 src/config/default.js 配置

谢谢

使用部分代碼和概念於

17koa2

koa2-server

参数传递问题请教

$
0
0

各位大神,请教个问题 以下代码 let name = “测试”; let text = ’ {“name”:“name”} '; 我想把"测试"传进去,打印出 ’ “name”:“测试” ’ 这样的字样,应该怎么处理啊,一定要带单引号的!!!

来分享一个我自己写的HTML模板引擎,Leopard

$
0
0

Leopard Build Statuscodecovnpm

背景

Leopard, yet another HTML template engine!

本着造轮子的初衷,我花了两天时间写了一个基于字符串的HTML模板引擎,取名叫“豹”,Leopard,希望它能像豹子一样灵活敏捷。

之前使用过的模板有ejsjade(后来改名叫pug)。前者设计得很容易上手,而且语法跟HTML比较接近。后者让人望而生畏,而且我没记错的话,jade对缩进有严格的要求,因为它是基于缩进来判断标签层级关系的,这样的设计让人编写的时候几乎是如履薄冰如写Python(我的游标卡尺呢???),所以我当时还是一直用ejs来开发的。

所以,这次我还是大致按照ejs的语法规范来实现Leopard

下载与使用

这里是github地址,欢迎大家看完之后在issue里提建议与bug,同时也欢迎提PR。

大家也可以通过npm来下载Leopard

$ npm install leopard-template

特性

目前而言,Leopard实现了以下功能点:

  • 插值:包括文本插值与HTML插值
  • 逻辑判断:ifelse
  • 循环:for循环,可以用来循环输出模板
  • 过滤器:支持在插值里加入过滤器,同时过滤器可以串联使用。引擎内置了两个过滤器,capitalizereverseLeopard同时支持自定义过滤器,可以使用Leopard.filter(filter, handler)来全局注册一个过滤器。在过滤器上,Leopard可能跟ejs的不太同,跟Vue的比较相似。

举个栗子

var Leopard = require('leopard-template')
var leo = new Leopard()

var template = '<% if (isOk) { %>' +
  '<span class=\"nickname\"><%= nickname | capitalize %></span>' +
  '<% } else { %>' +
  '<span class=\"realname\"><%= realname | capitalize %></span>' +
  '<% } %>'

var html = leo.compile(conditions, {
  isOk: false,
  nickname: 'leo',
  realname: 'leopard'
})

// html就是最终编译成功的的html了,可以直接通过document的方法渲染到页面上

性能

其实字符串模板引擎的性能大家都知道的,在现在的硬件条件下,几乎可以说是非常快的。(饱受虚拟DOM服务端渲染性能上不去的孩子哭晕在厕所,鄙人的公司项目就是卡在了这里上不了线)

我做了一个简单的benchmark,循环输出50,000个li耗时大概是在60ms左右。当然,Leopard现在还只支持将模板字符串解析编译成HTML字符串,所以这里的循环输出指的是字符串编译这一环。

# benchmark
$ npm run benchmark

开源

虽然说是个造轮子的项目,而且长得跟ejs几乎一毛一样,所以也不太可能投入到生产环境中使用(再者说现在都用MVVM框架来开发项目),但是我还是希望能按照开源项目的规范来开发Leopard。我给Leopard写了100%覆盖率的测试用例,每次提交commit也是跑完测试之后通过了才提交,也是希望这个项目不会太水。

# unit test
$ npm run test

# coverage
$ npm run coverage

结语

emmm…没什么好说的,提前祝大家新年大吉吧。

滴滴招聘高级/资深前端工程师

$
0
0

薪资: 20-40k 职位描述

  1. 实现与视觉稿、交互稿一致的跨平台、浏览器、客户端,兼容性好的移动端页面;
  2. 具有独挡一面的能力,能高质量的完成模块级的工作;
  3. 开发可重用模块,带领低阶同学一起进步。

任职要求

  1. 精通JavaScript/HTML5/CSS3等相关前端开发技术;
  2. 具有至少二年以上移动端网页开发;
  3. 掌握前端调试、性能优化、工程化(熟悉fis使用优先)开发等相关技术;
  4. 熟悉主流前后端模板引擎;
  5. 有WebApp、游戏、动画、图形等开发经验优先;
  6. 有PHP/NodeJS/HybridApp/Shell等开发经验优先;
  7. 对W3C标准发展保持持续关注,能主动跟进新技术发展动态优先。

接受简历邮箱: yangyiliang@didichuxing.com

node获取http响应头中的 cookie

$
0
0

koa2,监听 3000端口,返回 html,html中,有张图片是从远程下载的,图片 http响应中有 cookie,我要如何获取这个 cookie,客户端能否获取 document.cookie获取不到 图片.png

求问各路大神,单页面应用适合所有类型的系统吗?

$
0
0

如图,单页面应用(SPA) 适合应用于所有类型的系统吗,比如说 后台管理系统?


区块链相关项目 寻找志同道合的小伙伴

$
0
0

寻找前端 后台 志同道合的小伙伴 有兴趣的加我微信详聊 wechat: txlijintao QQ:772063721

node.js如何配置当用户输入http时自动跳到https请求?

$
0
0

在配置https的时候,怎么做到当用户在浏览器上输入http请求时自动跳到https,比如,用户输入:http://www.baidu.com,然后浏览器会变成https://www.baidu.com呢? 我自己配置的https只能通过https访问,输入http是无法访问?请问怎么解决?

【求助】:使用puppeteer怎么拿到控制台里面的请求到的数据?如图所示

$
0
0

untitled2.png酷狗播放音乐的界面: 我想获取我这个页面播放的音乐保存到本地 untitled1.png

大家好,看到很多企业招聘要求中需要数据库设计能力。什么是数据库设计能力?

nodemailer发邮件失败 unable to verify the first certificate

$
0
0

快过年了,要做个监控,需要用到发邮件的功能,下载了nodemailer,一路照着DEMO来,结果出现了个诡异的异常.

{ Error: unable to verify the first certificate
    at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:1092:38)
    at emitNone (events.js:86:13)
    at TLSSocket.emit (events.js:185:7)
    at TLSSocket._finishInit (_tls_wrap.js:610:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38) code: 'ECONNECTION', command: 'CONN' }

查了半天,网上说各种的都有,就是没这个错的描述,没办法翻墙去问Google,查到了一个,说是因为TLS的问题,不是nodemailer的锅,那么TLS出了什么问题?

回查了一下TLS的说明.找到了这么一条.

rejectUnauthorized <boolean> If not false the server will reject any connection which is not authorized with the list of supplied CAs. This option only has an effect if requestCert is true. Defaults to true.

也就是说,如果我的邮件服务器的证书不在CA里,就会被拒绝,那么好了,看样子是要把rejectUnauthorized设置成true, 再回头查nodemailer的说明,还好创建链接时,有个TLS的配置节点,所以配置改成:

let transporter = nodemailer.createTransport({
    host: 'mail.xxxxx.com',
    port:465,
    secure: true,
    auth: {
        user: "xxxx@xxxx.com",
        pass: "***********"
    },
    tls:{rejectUnauthorized: true}
});

问题解决,哈哈,这个年终于可以安心的过了.

缩减你的 Koa 控制器代码:更优雅的 RESTful 函数库

$
0
0

使用一行代码帮助你完成大部分的 RESTful 状态回复,使代码更简单而标准。 类似于:

ctx.ok() ctx.badRequest(‘user miss’) ctx.notFound({ name: ‘router’ })

仓库在这里:koa-custom-response话说我还写了好多有意思的类库和工具,懒得一个个贴链接啦,有兴趣的可以来看看 DhyanaChina,想要加入到这个组织里一起贡献代码的也可以留 github 邮箱喔~~

React Native 初尝试之 CNode 社区客户端开发

$
0
0

前言

最近踏上了学习使用 React Native 进行客户端开发的征途,因为之前的技术栈一直是 Vue, 在大致看了一下React Native 的相关介绍后,感觉有必要首先学习一下ReactJS。再看过相关文档后,以 CNode 社区的 API 上手体验了一下 React 的组件化开发方式,见 cnode-react-App。之后在边看文档边 Google 的过程中,完成了人生中第一次客户端开发。下文中将给出以 CNode 社区为原型进行React Native 开发过程中遇到的问题以及相关思考。

踩坑之路

实践出真知,虽然官方文档已经给出了详细的API以及教程,没有刻骨铭心的踩坑之旅,对于一些问题的理解可能也并不那么透彻。

Github 开源地址

https://github.com/monster1935/cnode-rn-app

App 预览

以下是 App 的部分截图:

已完成功能

目前在现有 CNode Api 的支持下,已经完成以下功能:

  • 分类的文章显示
  • 文章详情以及文章对应的评论展示,评论包括精彩评论和评论
  • 用户的收藏列表、消息列表页面
  • 设置、关于、github登录页面(部分页面仅提供了导航占位,后期逐步完善)
  • App 内部连接跳转至webview进行访问,点击更多可以刷新、跳转至浏览器访问
  • 搜索功能,鉴于目前未提供搜索的接口,目前实现为前端按照检索词进行搜索
  • 点击用户头像,跳转到用户信息详情页,展示该用户的最近发布以及最近回复
  • 部分操作的权限控制,比如点赞、收藏、收藏列表、信息列表
  • 扫码登录流程
  • 登录后的个人信息展示以及退出功能

尚未完成以及待优化功能

  • IOS 下的调试,目前仅仅测试了在 Android 下的表现
  • 回复、发帖功能
  • 添加代码区域的友好展示
  • 导航的跳转,比如点赞或者收藏时,未登录状态下用户需要跳转至登录页面,登录完成后应定位至点赞、收藏
  • 添加 App 启动页面
  • 用户详情页的动画存在一定问题
  • 异步接口请求的相关控制,组件销毁后,abort相关未完成的请求

技术栈

在开发过程中,用到了社区内较为优秀的一些开源贡献者提供的工具或者包,如下:

导航的实现 react-navigation

react-navigation 是 FaceBook 官方推荐使用的导航组件库,据称有着原生般的性能体验效果。使用起来也确实方便,在笔者进行开发的这段时间,react-navigation 的官方文档也进行了更新。官方文档还算详细,还有其他很多功能等待发掘。

图标 react-native-vector-icons

第三方的图标库,使用起来比较方便,项目中使用了 Ionicons的风格。

全局状态管理 react-redux & redux

使用了 react-redux 进行全局状态管理,主要涉及到登录后token, 用户信息以及文章列表的存储。相关需要登录才能使用的模块也需要获取到全局状态中的token,进行相应的判断。

html 转 view react-native-htmlview

涉及到 web 端 html 在 React Native 上的复用问题,因为两端在 布局、组件以及样式上的机制差异,html 完全的转换 view 不是很现实,但是在一定范围内实现转换还是可以的。react-native-htmlview 是目前做的较为优秀的,不过在笔者的使用过程中发现了一些问题,最终还是clone了其代码,又在本地修改才解决的,下文会详细解释。

持久化存储 react-native-storage

用于登录的token的持久化存储,每次启动 App 后,如果之前曾经登录不必重复登录。其不仅支持 React Native, 也提供了浏览器端的支持。

ActionSheet, 用于 webview 中的更多弹出面板 react-native-actionsheet

目前 app 中的链接均采用 app 内部的 webview 进行显示,显示的过程中添加了progress 进度条,并添加了刷新以及在浏览器中打开功能。

二维码扫描组件, 基于 react-native-camera的封装

基于 react-native-camera 封装的二维码扫码组件,思路借鉴了 react-native-qrcode的实现方法。

WebView 中的进度条显示 react-native-progress

一个更加友好的展示,在网页请求的过程中添加了顶部进度条

遇到的问题

1. react-navigation 中使用可滑动的tab view, 滑动不生效

初次使用react-navigation 后,在首页添加了react-native-scrollable-tab-view, 发现滚动根本不起作用,查阅了相关资料,设置 TabNavigator的 swipeEnabled: false即可。

2. 使用 react-native-htmlview 转换 html 字符串至 react native View 的过程,发现图片显示较小

在使用的过程中发现图片显示异常,查看其 issue,发现有同样的开发者遇到这样的问题。查阅相关资料,React Native Text Inline Image, 这篇文章中解释了为什么内嵌于 Text 中的 Image 在 Android 上显示过小的问题。原因在于 React Native 的内部的处理问题,React Native 在这种情况下直接以 图片的原始尺寸进行显示,并未再该尺寸的基础上乘以 图片的 PixelRatio。作者给出了一种解决办法就是封装一个InlineImage 组件,在传入的尺寸属性上手动乘以 PixelRatio

3. Android 上 Inline Image 通过 Image.getSize()后无法更新图片大小

一波未平,一波又起。刚弄明白 Inline Image 显示过小的问题,发现还是无法更加优雅的设置图片的尺寸。原始思路是通过 Image.getSize()后更新图片的尺寸。遗憾的是发现,图片不会更新大小,至今未发现原因。(持续跟进)

4. 动手修改 react-native-htmlview,完美解决 Image 显示问题

为了更加优雅的显示文章的图片,阅读了 react-native-htmlview 的源码,发现之所以会出现 Inline Image 的问题,主要原因是因为其 Image 是内嵌于 Text 节点,虽然其暴露了 NodeComponent 的 props, 不传的话默认为 Text。问题出现的原因,在于含有 img 标签的父标签被渲染为了 Text。因此在源码中添加了以下内容:

// 节点 后代中如果含有 img ,则该节点渲染为 View
function _contains(children) {
  for(let i = 0, len = children.length; i < len; i++) {
    if (children[i].type === 'tag' && children[i].name === 'img' || _contains(children[i].children || [])) {
      return true;
    }
  }
  return false;
}
...
// 标签如果是div 或者 含有img标签的父标签均渲染为View
if (node.type === 'tag') {
  if (node.name === 'div' || _contains(node.children)) {
    opts.NodeComponent = View;
  } else {
    opts.NodeComponent = Text;
  }
}

完美解决了 Image 的显示问题。

总结

React Native 的开发如果有 React 的开发经验,上手还是比较快的。主要是熟悉其组件的使用方式以及不同组件之间的区别。目前仅仅实现了一个 Demo 版本,渲染效率以及内存消耗等问题还未优化。后期对React Native 有深入的理解后,会进行相关方面的优化。

最后

技术学习的路上已经使用 CNodejs 的 Api 做过了好几个 demo,包括:

感谢 CNode社区提供的 Api,给广大开发者提供了学习练手的机会。


node发送邮件到kinddle

$
0
0

背景

平时给kinddle里面发送书籍都是通过邮件发送,每次都是打开浏览器上传附件等待…然后点击发送,时间久了就讨厌这种无聊的操作了,然后没事干就用node写了一个程序可以自动将本地目录下的文件自动发送到kinddle邮箱。

具体过程

创建一个目录来存放程序,凭自己的喜好啦。

  • 用命令行进入到新建的目录下安装邮件中间件,安装完成后可以看到多出一个文件夹

npm install nodemailer

  • 创建发送的代码,这个是主程序,里面分了三个部分。

    1. 获取附件
    2. 发送邮件
    3. 删除发送成功的附件
var nodemailer = require('nodemailer');  
var files=require("./getdir");
//读取文件完毕后发送邮件
var lists=files  //接收返回的附件数组信息
lists.then(function(arr){
     var AttArrObj=[];
     for(var i=0;i<arr.length;i++){
      var attobj=new Object();
      var filearr=arr[i].split("/");
      var filename=filearr[filearr.length-1]
      attobj.filename=filename
      attobj.path=arr[i];
      attobj.cid="kinddle"+i;
      AttArrObj.push(attobj)
     }
     console.log(AttArrObj)
     //导出后发送邮件
     var transporter = nodemailer.createTransport({  
      service: '126',  
      auth: {  
        user: '###@126.com',  
        pass: '###' //授权码,通过126 这里直接取126网站获取 
      
      }  
      });  
      var mailOptions = {  
        from: '###@126.com', // 发送者  
        to: '###@126.com,###@kindle.cn,###@kindle.cn', // 接受者,可以同时发送多个,以逗号隔开  
        subject: 'kinddle', // 标题  
        //text: 'Hello world', // 文本  
        html: `kinddle电子书`   ,
        attachments: AttArrObj   //附件信息
    
      };  
      
      transporter.sendMail(mailOptions, function (err, info) {  
        if (err) {  
          console.log(err);  
          return;  
        }  
      
        console.log('发送成功'); 
        //发送成功后删除目录下的所有文件
        var deletefiles=require("./getdirdelete");
      });  

 })

*获取附件

  var fs=require("fs");
var path="F:\kiddle";

function getfiles(path){
  return new Promise(function(resolve,reject){
    fs.readdir(path,function(err,files){
        if(err){
            console.log('error:\n' + err);
            resolve(err);
        }
        var arr=[];
        files.forEach(function(file){
            console.log('文件名:' + path + '/' + file);
            console.log(arr)
            arr.push(path + '/' + file)
            console.log(arr)
        })
        resolve(arr)
    })
  })
}

console.log(11)
var list=getfiles(path)
module.exports=list

// list.then(function(arr){
//     console.log("导出=="+arr)
//     exports.files=arr

// })

*删除附件

var fs=require("fs");
var path="F:\kiddle";

function getfiles(path){
  return new Promise(function(resolve,reject){
    fs.readdir(path,function(err,files){
        if(err){
            console.log('error:\n' + err);
            resolve(err);
        }
        var arr=[];
        files.forEach(function(file){
          
            console.log('清除文件名开始:' + path + '/' + file);
            fs.unlinkSync(path + '/' + file);
            console.log('清除文件名:' + path + '/' + file);
        })
        resolve(arr)
    })
  })
}

var list=getfiles(path)
module.exports=list

// list.then(function(arr){
//     console.log("导出=="+arr)
//     exports.files=arr

// })
  • 执行 node 主方法即可。

[求助]:puppeteer如果把headless:true,的话浏览器打开页面请求不到数据,反之,可以,有人遇到过吗?

$
0
0

[求助]:puppeteer如果把headless:true,的话浏览器打开页面请求不到数据,反之,可以,有人遇到过吗?这个页面 untitled1.png

Centos 从安装到部署之 自动化构建及部署(三)

$
0
0

本篇是 Centos 从安装到部署 系列文章的最后一篇。最近忙于其他事情,本该早就完成的终结篇拖了好久。

在 《Centos 从安装到部署之 Docker》中简单的讲解了一些 Docker 的基础知识,主要就是为本篇文章做一个前置铺垫。接下来将会为大家介绍如何通过借助 Daocloud 实现 Docker 镜像的自动构建及部署。

使用 Docker 进行应用部署的优势:

  1. 使用不同版本的镜像部署容器,轻松实现应用版本管理及控制,且方便移植
  2. 可以同时部署多个容器,实现单机集群化部署
  3. 依托第三方平台,轻松实现应用的持续集成、自动构建及部署
  4. 应用之间彼此隔离,降低环境维护成本,提高安全性

要实现的目标:

  1. 本地编写业务代码,无需构建

  2. 推送代码到 Github 仓库

  3. Daocloud 拉取最新代码进行镜像构建

  4. 构建完成自动部署镜像到指定服务器

    Talk is cheap, show me step!

一、编写 Dockerfile 文件

在 上一篇 中,我们了解到 Dockerfile 文件是构建 docker 镜像的 “指南”,Docker Daemon 会根据项目上下文中的 Dockerfile 文件中的指令将项目打包构建为一个镜像,所以编写 Dockerfile 文件是第一步。 首先我们在项目根目录下创建一个 Dockerfile 文件(本文的构建过程以我的个人项目 recatch 为例),然后在其中写入如下代码:

# 指定当前镜像的基础镜像为 node,版本为 8.9.1
FROM node:8.9.1

# 指定当前镜像维护人信息
MAINTAINER yvanwang googolewang@gmail.com

# 此处将项目根目录下的 package*.json 拷贝到 /tmp/文件夹下
COPY package*.json /tmp/

# 运行命令行指令切换执行上下文到 /tmp 下,并执行 npm install 命令进行第三方依赖包的安装。
# 之所以要在 /tmp/ 目录下安装 npm 包,是为了可以充分利用 docker 镜像层的缓存,
# 防止每次构建镜像都需要重新安装
RUN cd /tmp && npm install

# 运行命令创建 /usr/src/recatch 文件夹
RUN mkdir -p /usr/src/recatch

# 指定工作目录为 /usr/src/recatch
WORKDIR /usr/src/recatch

# 将项目根目录下的内容拷贝到镜像的 /usr/src/recatch 目录下
COPY . .

# 运行命令将安装的 npm 包 拷贝到/usr/src/recatch 目录下,并执行项目构建
RUN cp -a /tmp/node_modules /usr/src/recatch && npm run build

# 运行命令安装 pm2,我们将使用 pm2 来守护我们的 node 进程
RUN npm install pm2 -g

# 声明容器运行端口
EXPOSE 8084

# 容器启动命令,将会执行 package.json 中的 start:docker 脚本
CMD ["npm", "run", "start:docker"]

对配置指令进行简单介绍:

FROM:指定基础镜像,我们的镜像就是基于该基础镜像进行定制,所以在 Dockerfile 中 FROM 指令是必需的,而且必须是第一条指令

MAINTAINER:镜像维护人信息

COPY:复制文件,格式为:COPY <源路径> <目标路径>

RUN:是用来执行命令行命令的

WORKDIR:指定工作目录,格式为: WORKDIR <工作目录路径>

EXPOSE: 声明运行时容器提供服务端口,只是一个声明,容器运行端口以启动容器时的配置为主 

CMD: 容器启动命令,用于指定容器启动时需要运行的启动命令

详细具体的 Dockerfile 指令参考 《Docker — 从入门到实践》。

二、配置 Daocloud 设置 Github 项目

需要前往 Daocloud 注册一个管理账户,可以使用 Github 账户登录。 登录完成后,配置 Github 项目仓库。选择 项目 —> 创建新项目, 创建项目完成后,我们登录 Github,选择我们在 Daocloud 中选中配置的项目,切换到 Settings —> Webhooks 在菜单下可以看到一个 hook 配置。有了这个钩子配置,每次在我们提交代码之后,Github 就会向 Daocloud 发送一个 POST 请求,发送项目推送信息,Daocloud 接受到通知后就会自动执行镜像构建流程。

三、拉取镜像,运行容器

镜像构建完成后,设置 Daocloud 中的集群管理,配置我们的自有主机,拉取镜像并运行。选择 自有主机 —> 集群管理 —> 添加应用云平台 执行完成后选择 应用—>创建应用—>选择我们设置的项目 即可手动进行镜像部署。 至此,当我们的项目提交代码后, Daocloud 就会自动执行镜像构建,然后我们就可以部署镜像到我们的云主机,但是镜像部署这一步仍然需要我们手动执行。 万里长征就差最后一步,设置自动部署。选择 应用 —>我们创建的应用(点击应用名称)—>发布 将自动发布功能打开。

经过以上三步,我们就可以实现项目的自动构建和部署了。

本文旨在为大家提供一种使用 Docker 实现应用自动构建及部署的方法,如有不正确的地方,大家可以留言指出,共同学习,共同进步。

欢迎大家加入前端学习交流群 { 前端学习之同道中人 } :713117335

参考项目: recatch

参考资料: Docker — 从入门到实践Docker 五大优势 — 持续集成、版本控制、可移植性、隔离性和安全性

文章发布在我的个人博客:https://www.yvanwang.com/post/5a7fbb33dd37a80025577fa7原创文章作者:王亚飞 ( 如若转载,请注明出处 )

使用Typescript封装一款装饰器风格的Web框架

$
0
0

前言

自上一篇文章Nodejs:摆脱黑工坊发展出一款基础企业级框架写到,如何封装Nodejs的Koa框架之后,反响还算不错,多谢大家的支持。

不过,上次的文章由于发表在知乎,由于知乎排版非常难看,所以大家都没看爽。

经过几个星期的努力,每晚抽出一些时间,终于把教程重新写好了,这次的教程稍微有些改动,那就是使用Typescript封装一款装饰器风格的Web框架

具体是怎么样的呢?看图。

起因

最近一直在尝试、研究eggjs。大量使用typescript去编写逻辑(准备写一篇文章讲述一下一些坑)

在写egg的路由的时候,体验大概是这样的:

还不错,但是有两个不爽的地方:

  • 找地址:在编写controller的时候,有时候会忘记这个controller到底是什么地址,是什么method…
  • 每次写完逻辑,会忘记把controller的方法map到router.ts中去,也就是我图中说的,要来回切换文件修改。

官方的说法是,把路由集中化管理,使得我们更好的管理这些路由地址。

但是在实际中,我个人最理想的方式就是看见controller,就能知道这个函数是对应的什么地址和method。我不知道这是不是我python写多了的原因,实际上egg强大的插件机制能够实现这一点,我打算最近搞一款egg插件,支持装饰器

然后呢,我对其进行了小小的改造,使得eggjs能够支持装饰器路由,先来看看效果:

嘿嘿,好不错对不对?

至于怎么实现的,其实也很简单,直接在router导出的函数运行期间,用装饰器自动收集所有的路由,就可以了。

刚了一波源码

直接修改router行为,这个貌似不是太优雅,所以我在思考是不是能够自定义一个egg loader或者写一个egg-xxx插件什么的。

框架的定制那自然必须要对框架底层有所了解

因此一言不合,我直接去刚了一波源码,所以就有了这个教程,这个教程也算是我看了egg部分源码以后的一些心得,为了能够融汇贯通,我自己也仿照着写了一个,造了一波轮子。

但是和之前我造的轮子不同,这一次我记录下了整个造轮子的过程。写成了教程,分享给大家啦。

教程特色

相比上次的教程,有几大改进。

  1. Typescript:使用TS写成,使用装饰器(@)进行路由。
  2. 面向对象:controller和service全部以类方式书写
  3. 如何拓展koa的实例和koa的context对象
  4. 讲解controller和service的生命周期(与egg相同)
  5. 使用高级Api去处理controller和service的实例,实现高性能
  6. 更好的观看体验,在gitbook上。
  7. 每一个步骤的代码,我都保存下来了
  8. 免费的,但是是骗星的,觉得有收获,就点个星,给点动力
  9. 持续更新中…写了80%,还差实战部分以及多进程架构与进程间通信

目录

项目地址,书就在里面了:

项目地址:使用Typescript封装一款装饰器风格的Web框

  1. 大项目的标配Typescript
  2. 自动编译TS与服务器自动重启
  3. 路由拆分
  4. 引入Controller与Service的概念
  5. Controller的实现
  6. Service的实现
  7. 优雅的处理硬编码(配置)
  8. 小总结
  9. 路由去中心化
  10. 项目目录结构的变化
  11. (非必要)插件的实现
  12. 企业框架还欠缺的东西
  13. 抽离自己的框架burn.js

每一章节的后面都有对应的代码:

为了阅读更加舒适,我已经将教程写在Gitbook之中

最后

诶,又来写了一个轮子,这款轮子是是系列教程《使用Typescript封装一款装饰器风格的Web框架》配套框架,全部使用Typescript编写完成。

在教程中,你将比较深入的了解到如何使用typescript&js的面向对象封装,将koa一步步的封装成为一款类egg.js的框架。

这样,你能就更深入的了解eggjs,根基更加牢固,本教程也算是eggjs typescript的一个前置教程吧。

喜欢的,给点星星,是你给我最大的支持,感谢。

好久没发新东西了,嘿嘿嘿~

$
0
0

ts-template

ts-template嘿嘿嘿,一个基于模板字符串的模板引擎的最简实现~, 只适用于node环境,

usage 使用

模板字符串的语法,发挥想象吧,嘿嘿嘿~

test.js

const RenderClass = require('ts-template');

const renderVm = new RenderClass({
  rootName: 'root', // 数据跟字段 defaut: 'root'
  baseDir: '' // 模板根目录 defaut: path.join(process.cwd(), 'view');
  cache: true, // 是否缓存 defaut: true
})

renderVm.render('test.html', data)
renderVm.renderString('<div>${root.a} + ${root.b} = ${root.a + root.b}</div>', {
  a:1,
  b:2
})

test.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta name="format-detection" content="telephone=no">
  <title>ts-template</title>
  <style type="text/css">
    body {
      background: rebeccapurple;
    }
  </style>
  <script>
    var a = ${root.a};
  </script>
</head>

<body>
  include模板:
  ${await this.include('aa.html')}
  <div>嘿嘿嘿</div>
  1341<br>

  转意:
  ${e(root.b)}

  自运行函数:
  ${(() => { return 'adadfadfasdf' })()}
</body>

</html>

extension 扩展

const RenderClass = require('ts-template');
class SubRenderClass extends RenderClass {
  constructor(opt) {
    super(opt)
  }
  // format函数
  dateFormat(data, 'yyyy-MM-dd') {
    // ...
  }
  // async 函数
  async getFileData(fileName) {
    return new Promise((resolve, reject) => {
      fs.readFile(file, (err, data) => {
        if (err) {
          reject(err);
        } else {
          resolve(data.toString('utf-8'));
        }
      });
    });
  }
} 
const renderVm = new SubRenderClass({
  rootName: 'root', // 数据跟字段 defaut: 'root'
  baseDir: '' // 模板根目录 defaut: path.join(process.cwd(), 'view');
  cache: true, // 是否缓存 defaut: true
})

renderVm.renderString('<div>${_.dateFormat(root.time)}</div> <div>${await _.getFileData(root.file)}</div>', {
  time: 1518344445732,
  file: '/path/to/file.txt'
})
// 或者
renderVm.renderString('<div>${this.dateFormat(root.time)}</div> <div>${await this.getFileData(root.file)}</div>', {
  time: 1518344445732,
  file: '/path/to/file.txt'
})
Viewing all 14821 articles
Browse latest View live