精华内容
参与话题
问答
  • Egg.js 是一个简单的 JS 库。通过观察用户点击情况,你可以使用这个库在网页上添加复活节彩蛋效果。 标签:Eggjs 分享 window._bd_share_config = {...
  • 我第一次了解egg.js时候,感觉非常nb。稍微学了一下,结果后来又忘差不多了。 我现在养成了一种不写博客就感觉自己不会的习惯。就算当时会了,过段时间也忘了。 安装 先不用脚手架,熟悉下里面东西。 cnpm i egg ...

    前言

    • 我第一次了解egg.js时候,感觉非常nb。稍微学了一下,结果后来又忘差不多了。
    • 我现在养成了一种不写博客就感觉自己不会的习惯。就算当时会了,过段时间也忘了。
    • 官网
    • 插件
    • egg的构造有点像jekins里那个worker和master的感觉。node是单进程单线程,所以只使用一个cpu核,egg会做一个node集群,通过master来控制worker达到多核的利用。当客户端请求来时,会先发给master,master看哪个空闲,把请求发给哪个。如果哪个worker宕机了,就立即重启它。

    安装

    • 先不用脚手架,熟悉下里面东西。
    cnpm i egg --save
    cnpm i egg-bin --save-dev
    
    • 这个egg-bin就相当于我们经常配的package.json里script命令。通过script去执行egg-bin,这个再去执行egg。
    • 所以package.json里加上:
      "scripts": {
        "dev": "egg-bin dev"
      },
    

    编写controller

    • 如果你熟悉 Web 开发或 MVC,肯定猜到我们第一步需要编写的是 Controller 和 Router。
    • 新建个文件夹app,里面建个router.js
    module.exports = (app) => {
        const { router, controller } = app
        router.get('/mypage', controller.mypage.index)
    }
    
    • 这个会传入一个app,app上面挂了一堆东西,这里只需要router,和controller。controller是个对象,里面是文件夹controller下文件的实例,这里做了个文件叫mypage。
    • 在app下的controller文件夹下编写mypage.js文件:
    const { Controller } = require('egg')
    module.exports = class extends Controller {
        async index() {
            this.ctx.body = 'hello'
        }
    }
    
    • 这个类继承egg的controller,就是可以拿到它的一些方法。我们自己写的这个函数名,就是index,对应着上面传给router的controller.mypage.index。
    • 另外需要建立个默认配置。在app文件夹同级下建个config文件夹,里面建个config.default.js文件。

    config/config.default.js

    exports.keys = 'xx'
    
    • 随便给个key,优点像加盐算法里面的盐值的意思。
    • 然后使用npm run dev 启动,就能看见页面渲染的hello了。
    • 查看cookie,发现cookie里面有个csrf_token,这些都帮你搞定了。

    静态文件

    • app文件夹下面会有个public文件夹,没有这个文件夹会帮你建。
    • 在这个文件夹下随便建个文件,里面写上自己的内容,然后访问http://127.0.0.1:7001/public/你的文件名就可以访问了。

    使用模板引擎

    cnpm install egg-view-nunjucks --save
    
    • 先随意建个模板。需要在app下的view文件夹下。

    app/view/aaa.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
        <div>aaaaaaaaaaaaaaaaaaaaa</div>
        <div>
            {% for item in data %}
            <div> {{item.id}}</div>
            <div> {{item.title}}</div>
            {% endfor%}
        </div>
    </body>
    </html>
    
    • config.default.js需要改一下view的配置:

    config/config.default.js

    module.exports = app => {
        let config = {}
        config.keys = app.name + Date.now()
        config.view = {
            mapping: {
                defaultExtension: '.html',
                defaultViewEngine: 'nunjucks',
                '.html': 'nunjucks'
            }
        }
        return config
    }
    
    • 这个defaultExtension就是查找文件没给扩展名会默认加上扩展名html。
    • defaultViewEngine就是默认模板引擎是nunjucks。
    • .html就是扩展名为这个的使用nunjucks渲染。如果想用别的比如ejs就是'.html':'ejs'
    • config文件夹下再建个文件plugin.js:

    config/plugin.js

    exports.nunjucks = {
        enable: true,
        package: 'egg-view-nunjucks'
    }
    
    • 这个就是把插件开启。
    • 最后,还要修改controller,将前面写的mypage.js修改下,让其渲染页面。
    const { Controller } = require('egg')
    module.exports = class extends Controller {
        async index() {
            let { ctx } = this
            const data = [{ id: '111', title: '333' }, { id: '11221', title: '3341' }]
    
            await ctx.render('aaa', { data })
        }
    }
    
    • 这里的aaa就没给扩展名,因为配置了默认的。
    • 打开页面全部渲染出来就ok了。
    • 总结下就是配插件,配默认设置,ctx.render。

    调用远程接口

    • 在实际应用中,Controller 一般不会自己产出数据,也不会包含复杂的逻辑,复杂的过程应抽象为业务逻辑层 Service。
    • 先模拟个接口,新建个service.js,然后安装express和mockjs。
    let Mock = require('mockjs')
    let express = require('express')
    let app = express()
    app.get('/data', function (req, res) {
        let result = Mock.mock(
            {
                "code": 0,
                [`data|${req.query.limit}`]: [
                    { "id": "@id" },
                    { "title": "@csentence" }
                ]
            }
        )
        res.json(result)
    })
    app.listen(3000)
    
    • 访问 3000端口/data能有假数据,且使用查询?limit等于几就能显示几条就对了。
    • 然后,为了方便配置,我们可以在config.default.js里面的config对象上挂个属性,里面挂上url。
    module.exports = app => {
        let config = {}
        config.keys = app.name + Date.now()
        config.view = {
            mapping: {
                defaultExtension: '.html',
                defaultViewEngine: 'nunjucks',
                '.html': 'nunjucks'
            }
        }
        config.mypage = { url: '127.0.0.1:3000/data' }
        return config
    } 
    
    • 注意,config上不能直接挂字面量只能对象。上面配置的属性应该是被调用后传给真正的config对象的。另外使用他的curl方法会自己加http://,所以配置不用加。
    • 然后在app下建立service文件夹,写个mypageservice.js。文件夹名字是定死的,文件名没定死。
    const { Service } = require('egg')
    module.exports = class extends Service {
        async myback(limit) {
            let { ctx } = this
            let url = this.config.mypage.url
            let res = await ctx.curl(url, {
                method: 'GET',
                data: { limit },
                dataType: 'json'
    
            })
            return res.data.data
        }
    }
    
    • 这个service用来处理复杂逻辑,控制器调用service来获取结果。
    • 我们取的第一个data是数据外层大括号里面的data,第二个data是前面定义的假数据的data那个键。因为我们controller需要获取到数组嘛,这样取就能拿到数组了。
    • 这里需要继承egg的类,后面会调它。把他导出就行了。
    • 最后编写controller,调用service。
    const { Controller } = require('egg')
    module.exports = class extends Controller {
        async index() {
            let { ctx } = this
            let limit = ctx.query  ? ctx.query.limit : 5;
            let data = await this.service.mypageservice.myback(limit)
            await ctx.render('aaa', { data })
        }
    }
    
    • 这里是获取data是异步的,所以要用await。
    • this.service.xxx就是去找service文件夹下xxx文件实例。
    • 最后那个myback就是类里面的原型的方法名。
    • 刷新页面看是不是5条数据。修改查询参数,看是不是能返回对应条数的数据。

    计划任务

    • 我感觉计划任务真的是一个很6的设计。有需求建议看一下文档对于计划任务的说明。
    • 一般指有计划的做的任务,常见的是定时任务。
    • 计划任务放在app下的schedule文件夹。
    • 比如我有个数据需要每天改一次。那么我那个数据就不需要每次要时都去请求,而是应该每天去请求一次,然后缓存下,下次就直接从缓存拿就可以了。
    • 先写个接口,可以获取到数据,为了方便查看取数据没有,加个时间戳:
    app.get('/title', function (req, res) {
        res.json({ title: `每日更换标题${Date.now()}` })
    })
    
    • 在app下建立schedule文件夹,写个文件updateTitle.js。文件名不是定死的,文件夹名是定死的。

    app/schedule/updateTitle.js

    const { Subscription } = require('egg')
    module.exports = class extends Subscription {
        static get schedule() {
            return {
                interval: '5s',
                type: 'all'
            }
        }
        async subscribe() {
            let res = await this.ctx.curl(this.config.cache.url, {
                method: 'GET',
                dataType: 'json'
            })
            this.ctx.app.cache = res.data
        }
    }
    
    • 这里要继承egg的subscription基类。里面静态方法schedule和subscribe方法是定死必须要有的,不然报错。
    • 其中,schedule相当于任务配置,返回个对象,里面interval代表执行间隔,为了看出效果,我们设定为5s执行一次。
    • 执行逻辑就是subscribe,名字定死的。就是请求数据,把数据放到this.ctx.app.cache上。
    const { Controller } = require('egg')
    module.exports = class extends Controller {
        async index() {
            let { ctx } = this
            let limit = ctx.query ? ctx.query.limit : 5;
            let data = await this.service.mypageservice.myback(limit)
            await ctx.render('aaa', { data, title: ctx.app.cache ? ctx.app.cache.title : '默认' })
        }
    }
    
    • 在控制器中去获取缓存,如果有缓存,那么就拿缓存的,否则就走默认的。
    • 做到这里,实际计划任务第一次执行不会执行。所以需要让其在启动时拿到cache,这样渲染出的页面就一直不可能是默认了。
    • 第一次启动执行需要配置app.js。在app同目录下建立app.js。
    module.exports = app => {
        app.beforeStart(async () => {
            await app.runSchedule('updateTitle')
        })
    }
    
    • 这个updateTitle就是文件名,这样就会启动走一遍计划任务那个文件。
    展开全文
  • A Node.js framework based on Alibaba's Egg.js. 基于 Egg.js 的 Node.js 服务端基础框架。
  • plugin.js开启插件配置以及全局的app.js文件解析 plugin.js文件目录 代码如下 plugin.js // config/plugin.js 用于配置需要加载的插件 /** * plugin.js 中的每个配置项支持:(常用) * 1.{Boolean} enable - 是否...

    plugin.js开启插件配置以及全局的app.js文件解析

    plugin.js文件目录

    在这里插入图片描述

    代码如下

    plugin.js

    // config/plugin.js 用于配置需要加载的插件
    
    /**
     * plugin.js 中的每个配置项支持:(常用)
     *   1.{Boolean} enable - 是否开启此插件,默认为 true
     *   2.{String} package - npm 模块名称,通过 npm 模块形式引入插件
     * 
     */
    
    'use strict';
    
    /** @type Egg.EggPlugin */
    module.exports = {
      // had enabled by egg
      // static: {
      //   enable: true,
      // }
      //开启 egg-sequelize插件
      sequelize: {
        enable:true,
        package: "egg-sequelize"
      },
    
      //配置参数校验插件
      validate: {
        enable: true,
        package: "egg-validate"
      },
    
      //开启jwt
      jwt: {
        enable: true,
        package: "egg-jwt"
      },
    
      //开启passport和passport-jwt
      // passport:{
      //   enable: true,
      //   package: "egg-passport"
      // },
      // passportJwt: {
      //   enable: true,
      //   package: "egg-passport-jwt"
      // },
    
      //开启cors
      cors: {
        enable: true,
        package: "egg-cors"
      }
      
    };
    

    全局的app.js目录如下

    在这里插入图片描述

    代码如下

    app.js

    //app.js
    
    /**
     * Application 是全局应用对象,在一个应用中,只会实例化一个,在它上面可以挂载一些全局方法和对象
     * 
     * app 对象指的是 Koa 的全局应用对象,全局只有一个,在应用启动时被创建。
     * 
     * 在 app.js 中 app 对象会作为第一个参数注入到入口函数中
     * 
     * 框架提供了统一的入口文件(app.js)进行启动过程自定义,这个文件返回一个 Boot 类,我们可以通过定义 Boot 类中的生命周期方法来执行启动应用过程中的初始化工作
     * 
     */
    
    module.exports = app => {
        //自定义内容
        app.beforeStart(async() => {
            //应用会等待这个函数执行完成才启动
            console.log("生成模型和插入数据中");
            //根据定义好的model去数据库生成相应的表 force为true则会删除已经存在的表的数据
            //启动时创建数据库表
            await app.model.sync({force: false});
            console.log("生成模型和插入数据成功");
        });
    
        app.ready(async() => {
            console.log("==app ready==");
        });
    
        app.beforeClose(async() => {
            console.log("==app beforeClose==");
        });
        //该事件一个 worker 进程只会触发一次,在http服务完成启动后,会将http server 通过这个事件暴露给开发者
        app.once('server', server => {
            //websocket
        });
        //运行时有任何的异常被onerror插件捕获后,都会触发error事件,将错误对象和关联上下文(如果有)暴露给开发者,可以进行自定义的日志记录上报等处理
        app.on('error', (err, ctx) => {
            //report error
        });
        //应用收到请求和响应请求时,分别触发request和response事件,并将当前请求上下文暴露出来,开发者可以监听这两个事件进行日志记录
        app.on('request', ctx => {
            //log receive request
        });
        app.on('response', ctx => {
            //ctx.starttime is set by frameword
            //log total cost
        })
    }
    
    展开全文
  • 搭建egg.js服务器

    万次阅读 2020-06-01 10:46:24
    步骤两步 1.安装 cnpm i egg-init -g 2.初始化 egg-init --type=simple 3.依赖 cnpm i 4.运行 yarn dev

    步骤两步
    1.安装

    cnpm  i egg-init -g
    

    2.初始化

    egg-init --type=simple
    

    3.依赖

    cnpm i
    

    4.运行

    yarn dev
    
    展开全文
  • 使用pkg打包egg.js项目pkg原理安装pkg配置egg.js临时文件目录修改package.json文件配置打包入口文件pkg-build.js打包发布部署启动 pkg原理 pkg打包工具主要会按平台(支持window、mac、linux)分别打包。 pkg中会...

    pkg原理

    pkg打包工具主要会按平台(支持window、mac、linux)分别打包。
    pkg中会包含node的可执行文件,还会包含你要打包进去的代码。代码通过一个虚拟的文件系统把所有的代码和资源文件都挂载到 /snapshot/${被打包项目的文件夹名} 下面(pkg hack了 fs 的很多方法,拦截文件操作,如果发现读的文件路径是在挂载目录下就特殊处理,返回打包进去的文件信息,如果不在挂载目录下,则按node默认逻辑进行)
    pkg 会根据被打包项目的package.json 中的licence声明判断是否要对源码进行编译,npm上安装的依赖包基本都是开源的,会以源码的形式打包;而用户的源码如果没有声明开源的协议,则会把js文件编译为v8字节码进行保存(在项目中也就没法通过fs读取到源码,会给出抛错,即使是破解安装包也只能拿到v8字节码)

    安装pkg

     npm install pkg -g
    

    配置egg.js临时文件目录

    pkg的虚拟文件系统只是用来进行读文件操作,所有写相关都需要移动到包所在根目录。
    在config.default.js文件中配置如下:

      const process = require('process'),
          path = require('path');
      // 通过process.cwd()获取当前执行文件执行的路径
      config.rundir = process.cwd() + '/run';// 配置执行时临时文件的路径
      config.logger = {
        dir: path.join(process.cwd(), 'logs'),//配置普通日志文件地址
      };
      config.customLogger = {
        scheduleLogger: {
          file: path.join(process.cwd(), 'logs', 'egg-schedule.log'),//配置定时任务日志的地址
        },
      };
      config.static = { 
        dir: process.cwd() + '/public',
      };
    

    修改package.json文件

    由于Egg.js使用nanoid库所有egg.js项目打包时必须打入 ./node_modules/nanoid/**/*.js。egg-mysql、egg-redis等根据实际情况配置。目前发现的问题是不配置egg-redis可以正常挂载到ctx,但egg-mysql不会,所有建议用到的插件(plugin.js)全部配置,防止生产环境运行出错。
    scripts中配置pkg命令,打包时可直接运行npm run pkg

    {
    	"scripts": {
    	    "start": "egg-scripts start --daemon --title=egg-server-node-sso",
    	    "stop": "egg-scripts stop --title=egg-server-node-sso",
    	    "dev": "egg-bin dev",
    	    "debug": "egg-bin debug",
    	    "test": "npm run lint -- --fix && npm run test-local",
    	    "test-local": "egg-bin test",
    	    "cov": "egg-bin cov",
    	    "lint": "eslint .",
    	    "ci": "npm run lint && npm run cov",
    	    "autod": "autod",
    	    "pkgwin": "pkg . -t win --out-path ./dist --debug",
    	    "pkglinux": "pkg . -t linux --out-path /usr/dist --debug"
    	 },
    	 "bin": "pkg-build.js",
    	  "pkg": {
    	    "scripts": [
    	      "./app/**/*.js",
    	      "./config/**/*.js",
    	      "./app.js",
    	      "./agent.js"
    	    ],
    	    "assets": [
    	      "./app/view/**/*",
    	      "./public/**/*",
    	      "./node_modules/nanoid/**/*.js",
    	      "./node_modules/egg-mysql/**/*",   // 建议将用到的插件全部配置,防止生产环境运行出错
    	      "./node_modules/egg-view-nunjucks/**/*",
    	      "./node_modules/egg-redis/**/*"
    	    ]
    	  }
      }
    

    配置打包入口文件pkg-build.js

    pkg-build.js即为上述配置的bin路径文件。

     'use strict';
     console.log(__dirname);
     require(__dirname + '/node_modules/egg-scripts/bin/egg-scripts.js')
    

    打包发布

     // windows
     npm run pkgwin
     //linux
     npm run pkglinux
    

    可能遇到问题:
    第一次打包的时候,会遇到下包很慢很可能超时的问题。
    请到https://github.com/zeit/pkg-fetch/releases下载对应的包,然后复制到~/.pkh-cache/2.5/目录下。
    如果访问困难,可访问:
    windows版本 https://download.csdn.net/download/hazhijaio/12241215
    linux版本 https://download.csdn.net/download/hazhijaio/12241215
    mac版本 https://download.csdn.net/download/hazhijaio/12241215

    部署启动

    如果public目录非空,请将public复制到打包后的目录,运行以下命令即可。

     // windows
     appName.exe start {__dirname} 
     //linux
    ./appName start {__dirname} 
    
    展开全文

空空如也

1 2 3 4 5 ... 20
收藏数 9,487
精华内容 3,794
关键字:

egg