Skip to content

Commit

Permalink
feat: siteFile content support File URL
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Dec 13, 2024
1 parent 2b460f5 commit 878b014
Show file tree
Hide file tree
Showing 31 changed files with 159 additions and 66 deletions.
3 changes: 3 additions & 0 deletions example/helloworld-commonjs/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exports.index = async function index(ctx) {
ctx.body = 'hello egg';
};
3 changes: 3 additions & 0 deletions example/helloworld-commonjs/app/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = app => {
app.get('/', 'home.index');
};
1 change: 1 addition & 0 deletions example/helloworld-commonjs/config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.keys = 'hello world';
5 changes: 5 additions & 0 deletions example/helloworld-commonjs/config/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.schedule = {
enable: false,
};

exports.logrotator = false;
19 changes: 19 additions & 0 deletions example/helloworld-commonjs/index.js
Original file line number Diff line number Diff line change
@@ -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();
4 changes: 4 additions & 0 deletions example/helloworld-commonjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "hello-commonjs",
"type": "commonjs"
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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"
Expand Down
23 changes: 22 additions & 1 deletion src/app/middleware/site_file.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -7,9 +9,11 @@ export type SiteFileContentFun = (ctx: EggCoreContext) => Promise<Buffer | strin
export interface SiteFileMiddlewareOptions {
enable: boolean;
cacheControl: string;
[key: string]: string | Buffer | boolean | SiteFileContentFun;
[key: string]: string | Buffer | boolean | SiteFileContentFun | URL;
}

const BUFFER_CACHE = Symbol('siteFile URL buffer cache');

module.exports = (options: SiteFileMiddlewareOptions) => {
return async function siteFile(ctx: EggCoreContext, next: Next) {
if (ctx.method !== 'HEAD' && ctx.method !== 'GET') {
Expand All @@ -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 <xx..
// content is buffer
if (Buffer.isBuffer(content)) {
Expand Down
6 changes: 3 additions & 3 deletions src/config/config.default.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fs from 'node:fs';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import type { EggAppInfo } from '@eggjs/core';
import type { EggAppConfig } from '../lib/type.js';

Expand Down Expand Up @@ -189,7 +189,7 @@ export default (appInfo: EggAppInfo) => {
/**
* 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
Expand All @@ -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',
};
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/messenger/IMessenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 1 addition & 2 deletions src/lib/core/messenger/ipc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import { EventEmitter } from 'node:events';
import { debuglog } from 'node:util';
import workerThreads from 'node:worker_threads';
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/messenger/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion src/lib/egg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
7 changes: 7 additions & 0 deletions src/lib/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,10 @@ export interface EggAppConfig {

[prop: string]: any;
}

export type {
EggLogger,
} from 'egg-logger';
export type {
ILifecycleBoot,
} from '@eggjs/core';
Original file line number Diff line number Diff line change
@@ -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', () => {

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18.19.0)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18.19.0)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18.19.0)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18.19.0)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18.19.0)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18.19.0)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

it.only not permitted

Check warning on line 12 in test/app/middleware/site_file.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

it.only not permitted
return app.httpRequest()
.get('/favicon.ico')
.expect(res => assert(res.headers['content-type'].includes('icon')))
Expand Down Expand Up @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion test/asyncSupport.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18.19.0)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18.19.0)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 18)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 20)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 22)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18.19.0)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18.19.0)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (ubuntu-latest, 18)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 20)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (macos-latest, 22)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 20)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18.19.0)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18.19.0)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 22)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

describe.only not permitted

Check warning on line 4 in test/asyncSupport.test.ts

View workflow job for this annotation

GitHub Actions / Node.js / Test (windows-latest, 18)

describe.only not permitted
afterEach(restore);
let app: MockApplication;
before(async () => {
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/apps/app-router/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = function* () {
module.exports = async function () {
this.body = 'hello';
};
2 changes: 0 additions & 2 deletions test/fixtures/apps/app-router/config/config.default.js
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
'use strict';

exports.keys = 'test key';
5 changes: 5 additions & 0 deletions test/fixtures/apps/app-router/config/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.schedule = {
enable: false,
};

exports.logrotator = false;
5 changes: 5 additions & 0 deletions test/fixtures/apps/async-app/config/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.schedule = {
enable: false,
};

exports.logrotator = false;
3 changes: 3 additions & 0 deletions test/fixtures/apps/favicon-buffer/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = async function() {
this.body = 'home';
};
3 changes: 3 additions & 0 deletions test/fixtures/apps/favicon-buffer/app/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = app => {
app.get('/', app.controller.home);
};
5 changes: 5 additions & 0 deletions test/fixtures/apps/favicon-buffer/config/config.default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.siteFile = {
'/favicon.ico': Buffer.from('https://eggjs.org/favicon.ico'),
}

exports.keys = 'foo';
3 changes: 3 additions & 0 deletions test/fixtures/apps/favicon-buffer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "favicon-buffer"
}
4 changes: 1 addition & 3 deletions test/fixtures/apps/middlewares/app/controller/error.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = function*() {
module.exports = async function() {
foo.bar;
};
4 changes: 1 addition & 3 deletions test/fixtures/apps/middlewares/app/controller/home.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = function*() {
module.exports = async function() {
this.body = 'home';
};
2 changes: 0 additions & 2 deletions test/fixtures/apps/middlewares/app/router.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

module.exports = app => {
app.get('/', app.controller.home);
app.get('/error', app.controller.error);
Expand Down
2 changes: 0 additions & 2 deletions test/fixtures/apps/middlewares/config/config.default.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use strict';

const fs = require('fs');
const path = require('path');

Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/apps/middlewares/config/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
exports.schedule = {
enable: false,
};

exports.logrotator = false;
26 changes: 0 additions & 26 deletions test/lib/core/loader/load_router.test.js

This file was deleted.

Loading

0 comments on commit 878b014

Please sign in to comment.