From 878b01411696d0a2b75e69f24974b3e5f6506993 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Fri, 13 Dec 2024 16:42:46 +0800 Subject: [PATCH] feat: siteFile content support File URL --- .../app/controller/home.js | 3 ++ example/helloworld-commonjs/app/router.js | 3 ++ example/helloworld-commonjs/config/config.js | 1 + example/helloworld-commonjs/config/plugin.js | 5 +++ example/helloworld-commonjs/index.js | 19 ++++++++ example/helloworld-commonjs/package.json | 4 ++ package.json | 5 ++- src/app/middleware/site_file.ts | 23 +++++++++- src/config/config.default.ts | 6 +-- src/lib/core/messenger/IMessenger.ts | 2 +- src/lib/core/messenger/ipc.ts | 3 +- src/lib/core/messenger/local.ts | 2 +- src/lib/egg.ts | 4 +- src/lib/type.ts | 7 +++ .../{site_file.test.js => site_file.test.ts} | 43 ++++++++++++------- test/asyncSupport.test.ts | 2 +- .../apps/app-router/app/controller/home.js | 2 +- .../apps/app-router/config/config.default.js | 2 - .../fixtures/apps/app-router/config/plugin.js | 5 +++ test/fixtures/apps/async-app/config/plugin.js | 5 +++ .../favicon-buffer/app/controller/home.js | 3 ++ .../apps/favicon-buffer/app/router.js | 3 ++ .../favicon-buffer/config/config.default.js | 5 +++ .../fixtures/apps/favicon-buffer/package.json | 3 ++ .../apps/middlewares/app/controller/error.js | 4 +- .../apps/middlewares/app/controller/home.js | 4 +- test/fixtures/apps/middlewares/app/router.js | 2 - .../apps/middlewares/config/config.default.js | 2 - .../apps/middlewares/config/plugin.js | 5 +++ test/lib/core/loader/load_router.test.js | 26 ----------- test/lib/core/loader/load_router.test.ts | 22 ++++++++++ 31 files changed, 159 insertions(+), 66 deletions(-) create mode 100644 example/helloworld-commonjs/app/controller/home.js create mode 100644 example/helloworld-commonjs/app/router.js create mode 100644 example/helloworld-commonjs/config/config.js create mode 100644 example/helloworld-commonjs/config/plugin.js create mode 100644 example/helloworld-commonjs/index.js create mode 100644 example/helloworld-commonjs/package.json rename test/app/middleware/{site_file.test.js => site_file.test.ts} (74%) create mode 100644 test/fixtures/apps/app-router/config/plugin.js create mode 100644 test/fixtures/apps/async-app/config/plugin.js create mode 100644 test/fixtures/apps/favicon-buffer/app/controller/home.js create mode 100644 test/fixtures/apps/favicon-buffer/app/router.js create mode 100644 test/fixtures/apps/favicon-buffer/config/config.default.js create mode 100644 test/fixtures/apps/favicon-buffer/package.json create mode 100644 test/fixtures/apps/middlewares/config/plugin.js delete mode 100644 test/lib/core/loader/load_router.test.js create mode 100644 test/lib/core/loader/load_router.test.ts diff --git a/example/helloworld-commonjs/app/controller/home.js b/example/helloworld-commonjs/app/controller/home.js new file mode 100644 index 0000000000..acb38de085 --- /dev/null +++ b/example/helloworld-commonjs/app/controller/home.js @@ -0,0 +1,3 @@ +exports.index = async function index(ctx) { + ctx.body = 'hello egg'; +}; diff --git a/example/helloworld-commonjs/app/router.js b/example/helloworld-commonjs/app/router.js new file mode 100644 index 0000000000..a407c2187d --- /dev/null +++ b/example/helloworld-commonjs/app/router.js @@ -0,0 +1,3 @@ +module.exports = app => { + app.get('/', 'home.index'); +}; diff --git a/example/helloworld-commonjs/config/config.js b/example/helloworld-commonjs/config/config.js new file mode 100644 index 0000000000..19944025f1 --- /dev/null +++ b/example/helloworld-commonjs/config/config.js @@ -0,0 +1 @@ +exports.keys = 'hello world'; diff --git a/example/helloworld-commonjs/config/plugin.js b/example/helloworld-commonjs/config/plugin.js new file mode 100644 index 0000000000..d3697a6580 --- /dev/null +++ b/example/helloworld-commonjs/config/plugin.js @@ -0,0 +1,5 @@ +exports.schedule = { + enable: false, +}; + +exports.logrotator = false; diff --git a/example/helloworld-commonjs/index.js b/example/helloworld-commonjs/index.js new file mode 100644 index 0000000000..4e2277d3bd --- /dev/null +++ b/example/helloworld-commonjs/index.js @@ -0,0 +1,19 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { once } = require('node:events'); +const { Application } = require('../../dist/commonjs/index'); + +const app = new Application({ + baseDir: process.cwd(), + mode: 'single', +}); + +async function main() { + await app.ready(); + console.log('egg app ready'); + + const server = app.listen(7001); + await once(server, 'listening'); + console.log(`egg app server listening at http://localhost:${server.address().port}`); +} + +main(); diff --git a/example/helloworld-commonjs/package.json b/example/helloworld-commonjs/package.json new file mode 100644 index 0000000000..b880871fa3 --- /dev/null +++ b/example/helloworld-commonjs/package.json @@ -0,0 +1,4 @@ +{ + "name": "hello-commonjs", + "type": "commonjs" +} diff --git a/package.json b/package.json index b7e60298f2..ad6da83eef 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ ], "dependencies": { "@eggjs/cookies": "^3.0.0", - "@eggjs/core": "^6.0.2", + "@eggjs/core": "^6.0.3", "@eggjs/utils": "^4.0.2", "@types/accepts": "^1.3.5", "accepts": "^1.3.8", @@ -64,6 +64,7 @@ "@types/mocha": "^10.0.7", "@types/ms": "^0.7.34", "@types/node": "22", + "@types/supertest": "^6.0.2", "address": "2", "assert-file": "1", "coffee": "5", @@ -82,7 +83,7 @@ "runscript": "2", "sdk-base": "^4.2.1", "spy": "^1.0.0", - "supertest": "^6.2.4", + "supertest": "^7.0.0", "tshy": "^3.0.2", "tshy-after": "1", "typescript": "5" diff --git a/src/app/middleware/site_file.ts b/src/app/middleware/site_file.ts index 1ba848a3c9..9d69e1d27a 100644 --- a/src/app/middleware/site_file.ts +++ b/src/app/middleware/site_file.ts @@ -1,4 +1,6 @@ import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { readFile } from 'node:fs/promises'; import type { EggCoreContext } from '@eggjs/core'; import type { Next } from '../../lib/type.js'; @@ -7,9 +9,11 @@ export type SiteFileContentFun = (ctx: EggCoreContext) => Promise { return async function siteFile(ctx: EggCoreContext, next: Next) { if (ctx.method !== 'HEAD' && ctx.method !== 'GET') { @@ -35,6 +39,23 @@ module.exports = (options: SiteFileMiddlewareOptions) => { return ctx.redirect(content); } + // URL + if (content instanceof URL) { + if (content.protocol !== 'file:') { + return ctx.redirect(content.href); + } + // protocol = file: + let buffer = Reflect.get(content, BUFFER_CACHE) as Buffer; + if (!buffer) { + buffer = await readFile(fileURLToPath(content)); + Reflect.set(content, BUFFER_CACHE, buffer); + } + ctx.set('cache-control', options.cacheControl); + ctx.body = content; + ctx.type = path.extname(ctx.path); + return; + } + // '/robots.txt': Buffer { /** * The option of `siteFile` middleware * - * You can map some files using this options, it will response immdiately when matching. + * You can map some files using this options, it will response immediately when matching. * * @member {Object} Config#siteFile - key is path, and value is url or buffer. * @property {String} cacheControl - files cache , default is public, max-age=2592000 @@ -201,7 +201,7 @@ export default (appInfo: EggAppInfo) => { */ config.siteFile = { enable: true, - '/favicon.ico': fs.readFileSync(path.join(__dirname, 'favicon.png')), + '/favicon.ico': pathToFileURL(path.join(__dirname, 'favicon.png')), // default cache in 30 days cacheControl: 'public, max-age=2592000', }; diff --git a/src/lib/core/messenger/IMessenger.ts b/src/lib/core/messenger/IMessenger.ts index 4ca184aef3..8f4ac5d757 100644 --- a/src/lib/core/messenger/IMessenger.ts +++ b/src/lib/core/messenger/IMessenger.ts @@ -50,7 +50,7 @@ export interface IMessenger extends EventEmitter { * @param {String} to - let master know how to send message * @return {Messenger} this */ - send(action: string, data: unknown | undefined, to: string): IMessenger; + send(action: string, data: unknown | undefined, to?: string): IMessenger; close(): void; diff --git a/src/lib/core/messenger/ipc.ts b/src/lib/core/messenger/ipc.ts index fdf165d7a3..94979421d3 100644 --- a/src/lib/core/messenger/ipc.ts +++ b/src/lib/core/messenger/ipc.ts @@ -1,4 +1,3 @@ - import { EventEmitter } from 'node:events'; import { debuglog } from 'node:util'; import workerThreads from 'node:worker_threads'; @@ -107,7 +106,7 @@ export class Messenger extends EventEmitter implements IMessenger { * @param {String} to - let master know how to send message * @return {Messenger} this */ - send(action: string, data: unknown | undefined, to: string): Messenger { + send(action: string, data: unknown | undefined, to?: string): Messenger { sendmessage(process, { action, data, diff --git a/src/lib/core/messenger/local.ts b/src/lib/core/messenger/local.ts index 99fa991b2b..6bbf228b04 100644 --- a/src/lib/core/messenger/local.ts +++ b/src/lib/core/messenger/local.ts @@ -93,7 +93,7 @@ export class Messenger extends EventEmitter implements IMessenger { * @param {String} to - let master know how to send message * @return {Messenger} this */ - send(action: string, data: unknown | undefined, to: string): Messenger { + send(action: string, data: unknown | undefined, to?: string): Messenger { // use nextTick to keep it async as IPC messenger process.nextTick(() => { const { egg } = this; diff --git a/src/lib/egg.ts b/src/lib/egg.ts index 4001165056..4ecdf2c61d 100644 --- a/src/lib/egg.ts +++ b/src/lib/egg.ts @@ -144,7 +144,9 @@ export class EggApplicationCore extends EggCore { this.messenger.once('egg-ready', () => { this.lifecycle.triggerServerDidReady(); }); - this.load(); + this.lifecycle.registerBeforeStart(async () => { + await this.load(); + }, 'load files'); } protected async loadConfig() { diff --git a/src/lib/type.ts b/src/lib/type.ts index 603591fef8..8f6ed92a46 100644 --- a/src/lib/type.ts +++ b/src/lib/type.ts @@ -327,3 +327,10 @@ export interface EggAppConfig { [prop: string]: any; } + +export type { + EggLogger, +} from 'egg-logger'; +export type { + ILifecycleBoot, +} from '@eggjs/core'; diff --git a/test/app/middleware/site_file.test.js b/test/app/middleware/site_file.test.ts similarity index 74% rename from test/app/middleware/site_file.test.js rename to test/app/middleware/site_file.test.ts index 180a628747..17330b47a3 100644 --- a/test/app/middleware/site_file.test.js +++ b/test/app/middleware/site_file.test.ts @@ -1,17 +1,15 @@ -'use strict'; +import { strict as assert } from 'node:assert'; +import { createApp, type MockApplication } from '../../utils.js'; -const assert = require('assert'); -const utils = require('../../utils'); - -describe('test/app/middleware/site_file.test.js', () => { - let app; +describe('test/app/middleware/site_file.test.ts', () => { + let app: MockApplication; before(() => { - app = utils.app('apps/middlewares'); + app = createApp('apps/middlewares'); return app.ready(); }); after(() => app.close()); - it('should GET /favicon.ico 200', () => { + it.only('should GET /favicon.ico 200', () => { return app.httpRequest() .get('/favicon.ico') .expect(res => assert(res.headers['content-type'].includes('icon'))) @@ -74,9 +72,9 @@ describe('test/app/middleware/site_file.test.js', () => { }); describe('custom favicon', () => { - let app; + let app: MockApplication; before(() => { - app = utils.app('apps/favicon'); + app = createApp('apps/favicon'); return app.ready(); }); after(() => app.close()); @@ -87,15 +85,30 @@ describe('test/app/middleware/site_file.test.js', () => { .expect(302) .expect(res => { assert(!res.headers['set-cookie']); - assert(res.headers.location === 'https://eggjs.org/favicon.ico'); + assert.equal(res.headers.location, 'https://eggjs.org/favicon.ico'); }); }); }); + describe('custom favicon with Buffer content', () => { + let app: MockApplication; + before(() => { + app = createApp('apps/favicon-buffer'); + return app.ready(); + }); + after(() => app.close()); + + it('should redirect https://eggjs.org/favicon.ico', () => { + return app.httpRequest() + .get('/favicon.ico') + .expect(200); + }); + }); + describe('custom favicon with function', () => { - let app; + let app: MockApplication; before(() => { - app = utils.app('apps/favicon-function'); + app = createApp('apps/favicon-function'); return app.ready(); }); after(() => app.close()); @@ -112,9 +125,9 @@ describe('test/app/middleware/site_file.test.js', () => { }); describe('siteFile.cacheControl = no-store', () => { - let app; + let app: MockApplication; before(() => { - app = utils.app('apps/siteFile-custom-cacheControl'); + app = createApp('apps/siteFile-custom-cacheControl'); return app.ready(); }); after(() => app.close()); diff --git a/test/asyncSupport.test.ts b/test/asyncSupport.test.ts index ea161337b0..e169abc8fb 100644 --- a/test/asyncSupport.test.ts +++ b/test/asyncSupport.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'node:assert'; import { createApp, restore, MockApplication } from './utils.js'; -describe('test/asyncSupport.test.ts', () => { +describe.only('test/asyncSupport.test.ts', () => { afterEach(restore); let app: MockApplication; before(async () => { diff --git a/test/fixtures/apps/app-router/app/controller/home.js b/test/fixtures/apps/app-router/app/controller/home.js index 24901f6eec..6179479a06 100644 --- a/test/fixtures/apps/app-router/app/controller/home.js +++ b/test/fixtures/apps/app-router/app/controller/home.js @@ -1,3 +1,3 @@ -module.exports = function* () { +module.exports = async function () { this.body = 'hello'; }; diff --git a/test/fixtures/apps/app-router/config/config.default.js b/test/fixtures/apps/app-router/config/config.default.js index 1c7cb2ea03..be3700e09d 100644 --- a/test/fixtures/apps/app-router/config/config.default.js +++ b/test/fixtures/apps/app-router/config/config.default.js @@ -1,3 +1 @@ -'use strict'; - exports.keys = 'test key'; diff --git a/test/fixtures/apps/app-router/config/plugin.js b/test/fixtures/apps/app-router/config/plugin.js new file mode 100644 index 0000000000..d3697a6580 --- /dev/null +++ b/test/fixtures/apps/app-router/config/plugin.js @@ -0,0 +1,5 @@ +exports.schedule = { + enable: false, +}; + +exports.logrotator = false; diff --git a/test/fixtures/apps/async-app/config/plugin.js b/test/fixtures/apps/async-app/config/plugin.js new file mode 100644 index 0000000000..d3697a6580 --- /dev/null +++ b/test/fixtures/apps/async-app/config/plugin.js @@ -0,0 +1,5 @@ +exports.schedule = { + enable: false, +}; + +exports.logrotator = false; diff --git a/test/fixtures/apps/favicon-buffer/app/controller/home.js b/test/fixtures/apps/favicon-buffer/app/controller/home.js new file mode 100644 index 0000000000..962f8fcba9 --- /dev/null +++ b/test/fixtures/apps/favicon-buffer/app/controller/home.js @@ -0,0 +1,3 @@ +module.exports = async function() { + this.body = 'home'; +}; diff --git a/test/fixtures/apps/favicon-buffer/app/router.js b/test/fixtures/apps/favicon-buffer/app/router.js new file mode 100644 index 0000000000..fa70390f6a --- /dev/null +++ b/test/fixtures/apps/favicon-buffer/app/router.js @@ -0,0 +1,3 @@ +module.exports = app => { + app.get('/', app.controller.home); +}; diff --git a/test/fixtures/apps/favicon-buffer/config/config.default.js b/test/fixtures/apps/favicon-buffer/config/config.default.js new file mode 100644 index 0000000000..908c473727 --- /dev/null +++ b/test/fixtures/apps/favicon-buffer/config/config.default.js @@ -0,0 +1,5 @@ +exports.siteFile = { + '/favicon.ico': Buffer.from('https://eggjs.org/favicon.ico'), +} + +exports.keys = 'foo'; diff --git a/test/fixtures/apps/favicon-buffer/package.json b/test/fixtures/apps/favicon-buffer/package.json new file mode 100644 index 0000000000..258f5343a2 --- /dev/null +++ b/test/fixtures/apps/favicon-buffer/package.json @@ -0,0 +1,3 @@ +{ + "name": "favicon-buffer" +} diff --git a/test/fixtures/apps/middlewares/app/controller/error.js b/test/fixtures/apps/middlewares/app/controller/error.js index cb77197ac9..4fcacbe62d 100644 --- a/test/fixtures/apps/middlewares/app/controller/error.js +++ b/test/fixtures/apps/middlewares/app/controller/error.js @@ -1,5 +1,3 @@ -'use strict'; - -module.exports = function*() { +module.exports = async function() { foo.bar; }; diff --git a/test/fixtures/apps/middlewares/app/controller/home.js b/test/fixtures/apps/middlewares/app/controller/home.js index ac412a98d8..962f8fcba9 100644 --- a/test/fixtures/apps/middlewares/app/controller/home.js +++ b/test/fixtures/apps/middlewares/app/controller/home.js @@ -1,5 +1,3 @@ -'use strict'; - -module.exports = function*() { +module.exports = async function() { this.body = 'home'; }; diff --git a/test/fixtures/apps/middlewares/app/router.js b/test/fixtures/apps/middlewares/app/router.js index 1b2c9c53bf..517513d1b2 100644 --- a/test/fixtures/apps/middlewares/app/router.js +++ b/test/fixtures/apps/middlewares/app/router.js @@ -1,5 +1,3 @@ -'use strict'; - module.exports = app => { app.get('/', app.controller.home); app.get('/error', app.controller.error); diff --git a/test/fixtures/apps/middlewares/config/config.default.js b/test/fixtures/apps/middlewares/config/config.default.js index 21f2835daf..80e6f1bf5f 100644 --- a/test/fixtures/apps/middlewares/config/config.default.js +++ b/test/fixtures/apps/middlewares/config/config.default.js @@ -1,5 +1,3 @@ -'use strict'; - const fs = require('fs'); const path = require('path'); diff --git a/test/fixtures/apps/middlewares/config/plugin.js b/test/fixtures/apps/middlewares/config/plugin.js new file mode 100644 index 0000000000..d3697a6580 --- /dev/null +++ b/test/fixtures/apps/middlewares/config/plugin.js @@ -0,0 +1,5 @@ +exports.schedule = { + enable: false, +}; + +exports.logrotator = false; diff --git a/test/lib/core/loader/load_router.test.js b/test/lib/core/loader/load_router.test.js deleted file mode 100644 index 1627d549a5..0000000000 --- a/test/lib/core/loader/load_router.test.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -const pedding = require('pedding'); -const utils = require('../../../utils'); - -describe('test/lib/core/loader/load_router.test.js', () => { - let app; - before(() => { - app = utils.app('apps/app-router'); - return app.ready(); - }); - after(() => app.close()); - - it('should load app/router.js', done => { - done = pedding(2, done); - app.httpRequest() - .get('/') - .expect(200) - .expect('hello', done); - - app.httpRequest() - .get('/home') - .expect(200) - .expect('hello', done); - }); -}); diff --git a/test/lib/core/loader/load_router.test.ts b/test/lib/core/loader/load_router.test.ts new file mode 100644 index 0000000000..4b1d4218f6 --- /dev/null +++ b/test/lib/core/loader/load_router.test.ts @@ -0,0 +1,22 @@ +import { createApp, MockApplication } from '../../../utils.js'; + +describe('test/lib/core/loader/load_router.test.ts', () => { + let app: MockApplication; + before(() => { + app = createApp('apps/app-router'); + return app.ready(); + }); + after(() => app.close()); + + it('should load app/router.js', async () => { + await app.httpRequest() + .get('/') + .expect(200) + .expect('hello'); + + await app.httpRequest() + .get('/home') + .expect(200) + .expect('hello'); + }); +});