diff --git a/.eslintrc b/.eslintrc index c799fe5..9bcdb46 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,3 +1,6 @@ { - "extends": "eslint-config-egg" + "extends": [ + "eslint-config-egg/typescript", + "eslint-config-egg/lib/rules/enforce-node-prefix" + ] } diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 48f9944..0000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,24 +0,0 @@ - - -##### Checklist - - -- [ ] `npm test` passes -- [ ] tests and/or benchmarks are included -- [ ] documentation is changed or added -- [ ] commit message follows commit guidelines - -##### Affected core subsystem(s) - - - -##### Description of change - diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 4ab6da1..fd73aac 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -3,16 +3,14 @@ name: CI on: push: branches: [ master ] - pull_request: branches: [ master ] - workflow_dispatch: {} - jobs: Job: name: Node.js - uses: artusjs/github-actions/.github/workflows/node-test.yml@v1 + uses: node-modules/github-actions/.github/workflows/node-test.yml@master with: - os: 'ubuntu-latest, windows-latest' - version: '14, 16, 18' + version: '18.19.0, 20, 22' + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml new file mode 100644 index 0000000..bac3fac --- /dev/null +++ b/.github/workflows/pkg.pr.new.yml @@ -0,0 +1,23 @@ +name: Publish Any Commit +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run prepublishOnly --if-present + + - run: npx pkg-pr-new publish diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2561997..a2bf04a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,16 +1,13 @@ name: Release + on: push: branches: [ master ] - workflow_dispatch: {} - jobs: release: name: Node.js - uses: artusjs/github-actions/.github/workflows/node-release.yml@v1 + uses: eggjs/github-actions/.github/workflows/node-release.yml@master secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GIT_TOKEN: ${{ secrets.GIT_TOKEN }} - with: - checkTest: false diff --git a/.gitignore b/.gitignore index b4fecda..c010914 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,10 @@ logs/ npm-debug.log node_modules/ coverage/ -run/ +test/fixtures/**/run +.DS_Store +.tshy* +.eslintcache +dist +package-lock.json +.package-lock.json diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb384f..6df36cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,3 +13,76 @@ ### Features * add contributors ([3bf1ba1](https://github.com/eggjs/egg-static/commit/3bf1ba1b6bafd4b1a61b9fb0438c4ec07939af37)) + +--- + + +2.2.0 / 2019-02-15 +================== + +**features** + * [[`7a4b927`](http://github.com/eggjs/egg-static/commit/7a4b927e53670af89005fde057c838825fe96a30)] - feat: add options.dir for support multi folder serve. (#17) (仙森 <>) + +2.1.1 / 2018-05-02 +================== + +**fixes** + * [[`a55f7ad`](http://github.com/eggjs/egg-static/commit/a55f7ad50ab880f3114bf12910f5f64e1d4da941)] - fix: range only work with static prefix url (#15) (Yiyu He <>) + +2.1.0 / 2018-01-10 +================== + +**features** + * [[`cd35dea`](http://github.com/eggjs/egg-static/commit/cd35dea2ccf98dc7fed7d36a25f5555f3712eb8f)] - feat: add range support (#13) (HelloYou <>) + +**others** + * [[`93a56c1`](http://github.com/eggjs/egg-static/commit/93a56c1af60c69cd814d33696224a7f044034da6)] - docs: fix confusion for option:prefix (#12) (Airyland <>) + +2.0.0 / 2017-11-09 +================== + +**others** + * [[`bc2d05c`](http://github.com/eggjs/egg-static/commit/bc2d05c10fe6aabc3e0190a20866dd45f4134dda)] - refactor: upgrade dependencies and support egg@2 (#11) (Yiyu He <>) + * [[`779e4fa`](http://github.com/eggjs/egg-static/commit/779e4fa7d171fa7e1c51c902e9b47be9632cb35d)] - docs: update usage (#10) (TZ | 天猪 <>) + +1.4.1 / 2017-06-04 +================== + + * docs: fix License url (#9) + +1.4.0 / 2017-06-01 +================== + + * feat: use lru to store files (#8) + +1.3.0 / 2017-03-25 +================== + + * feat: add support multiple directory (#7) + +1.2.0 / 2017-02-21 +================== + + * deps: upgrade koa-static-cache to 4.x (#6) + * chore: upgrade deps and fix test (#5) + +1.1.0 / 2017-01-13 +================== + + * feat: default lazyload (#4) + * docs: note for koa-static-cache (#3) + +1.0.0 / 2016-11-02 +================== + + * test: add node v7 (#2) + +0.1.0 / 2016-07-18 +================== + + * test: add tests (#1) + +0.0.2 / 2016-07-15 +================== + + * init diff --git a/History.md b/History.md deleted file mode 100644 index e72c50c..0000000 --- a/History.md +++ /dev/null @@ -1,70 +0,0 @@ - -2.2.0 / 2019-02-15 -================== - -**features** - * [[`7a4b927`](http://github.com/eggjs/egg-static/commit/7a4b927e53670af89005fde057c838825fe96a30)] - feat: add options.dir for support multi folder serve. (#17) (仙森 <>) - -2.1.1 / 2018-05-02 -================== - -**fixes** - * [[`a55f7ad`](http://github.com/eggjs/egg-static/commit/a55f7ad50ab880f3114bf12910f5f64e1d4da941)] - fix: range only work with static prefix url (#15) (Yiyu He <>) - -2.1.0 / 2018-01-10 -================== - -**features** - * [[`cd35dea`](http://github.com/eggjs/egg-static/commit/cd35dea2ccf98dc7fed7d36a25f5555f3712eb8f)] - feat: add range support (#13) (HelloYou <>) - -**others** - * [[`93a56c1`](http://github.com/eggjs/egg-static/commit/93a56c1af60c69cd814d33696224a7f044034da6)] - docs: fix confusion for option:prefix (#12) (Airyland <>) - -2.0.0 / 2017-11-09 -================== - -**others** - * [[`bc2d05c`](http://github.com/eggjs/egg-static/commit/bc2d05c10fe6aabc3e0190a20866dd45f4134dda)] - refactor: upgrade dependencies and support egg@2 (#11) (Yiyu He <>) - * [[`779e4fa`](http://github.com/eggjs/egg-static/commit/779e4fa7d171fa7e1c51c902e9b47be9632cb35d)] - docs: update usage (#10) (TZ | 天猪 <>) - -1.4.1 / 2017-06-04 -================== - - * docs: fix License url (#9) - -1.4.0 / 2017-06-01 -================== - - * feat: use lru to store files (#8) - -1.3.0 / 2017-03-25 -================== - - * feat: add support multiple directory (#7) - -1.2.0 / 2017-02-21 -================== - - * deps: upgrade koa-static-cache to 4.x (#6) - * chore: upgrade deps and fix test (#5) - -1.1.0 / 2017-01-13 -================== - - * feat: default lazyload (#4) - * docs: note for koa-static-cache (#3) - -1.0.0 / 2016-11-02 -================== - - * test: add node v7 (#2) - -0.1.0 / 2016-07-18 -================== - - * test: add tests (#1) - -0.0.2 / 2016-07-15 -================== - - * init diff --git a/README.md b/README.md index 749f9e0..4854747 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,32 @@ -# egg-static +# @eggjs/static [![NPM version][npm-image]][npm-url] +[![Node.js CI](https://github.com/eggjs/static/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/static/actions/workflows/nodejs.yml) [![Test coverage][codecov-image]][codecov-url] +[![Known Vulnerabilities][snyk-image]][snyk-url] [![npm download][download-image]][download-url] +[![Node.js Version](https://img.shields.io/node/v/@eggjs/static.svg?style=flat)](https://nodejs.org/en/download/) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com) -[npm-image]: https://img.shields.io/npm/v/egg-static.svg?style=flat-square -[npm-url]: https://npmjs.org/package/egg-static -[codecov-image]: https://codecov.io/github/eggjs/egg-static/coverage.svg?branch=master -[codecov-url]: https://codecov.io/github/eggjs/egg-static?branch=master -[download-image]: https://img.shields.io/npm/dm/egg-static.svg?style=flat-square -[download-url]: https://npmjs.org/package/egg-static +[npm-image]: https://img.shields.io/npm/v/@eggjs/static.svg?style=flat-square +[npm-url]: https://npmjs.org/package/@eggjs/static +[codecov-image]: https://img.shields.io/codecov/c/github/eggjs/static.svg?style=flat-square +[codecov-url]: https://codecov.io/github/eggjs/static?branch=master +[snyk-image]: https://snyk.io/test/npm/@eggjs/static/badge.svg?style=flat-square +[snyk-url]: https://snyk.io/test/npm/@eggjs/static +[download-image]: https://img.shields.io/npm/dm/@eggjs/static.svg?style=flat-square +[download-url]: https://npmjs.org/package/@eggjs/static -Static server plugin for egg, base on [koa-static-cache](https://github.com/koajs/static-cache). +Static server plugin for egg, base on [@eggjs/koa-static-cache](https://github.com/eggjs/koa-static-cache). ## Install -`egg-static` is a plugin that has been built-in for egg. It is enabled by default. +`@eggjs/static` is a plugin that has been built-in for egg. It is enabled by default. ## Configuration -egg-static support all configurations in [koa-static-cache](https://github.com/koajs/static-cache). and with default configurations below: +`@eggjs/static` support all configurations in [@eggjs/koa-static-cache](https://github.com/eggjs/koa-static-cache). +And with default configurations below: - prefix: `'/public/'` - dir: `path.join(appInfo.baseDir, 'app/public')` @@ -28,20 +35,22 @@ egg-static support all configurations in [koa-static-cache](https://github.com/k - maxAge: `31536000` in prod env, `0` in other envs - buffer: `true` in prod env, `false` in other envs -`egg-static` provides one more option: +`@eggjs/static` provides one more option: - maxFiles: the maximum value of cache items, only effective when dynamic is true, default is `1000`. **All static files in `$baseDir/app/public` can be visited with prefix `/public`, and all the files are lazy loaded.** - In non-production environment, assets won't be cached, your modification can take effect immediately. -- In production environment, `egg-static` will cache the assets after visited, you need to restart the process to update the assets. +- In production environment, `@eggjs/static` will cache the assets after visited, you need to restart the process to update the assets. - Dir default is `$baseDir/app/public` but you can also define **multiple directory** by use `dir: [dir1, dir2, ...]` or `dir: [dir1, { prefix: '/static2', dir: dir2 }]`, static server will use all these directories. -```js -// {app_root}/config/config.default.js -exports.static = { - // maxAge: 31536000, +```ts +// {app_root}/config/config.default.ts +export default { + static: { + // maxAge: 31536000, + }, }; ``` @@ -51,16 +60,10 @@ Please open an issue [here](https://github.com/eggjs/egg/issues). ## License -[MIT](https://github.com/eggjs/egg-static/blob/master/LICENSE) - - +[MIT](LICENSE) ## Contributors -|[
dead-horse](https://github.com/dead-horse)
|[
fengmk2](https://github.com/fengmk2)
|[
atian25](https://github.com/atian25)
|[
popomore](https://github.com/popomore)
|[
okoala](https://github.com/okoala)
|[
airyland](https://github.com/airyland)
| -| :---: | :---: | :---: | :---: | :---: | :---: | -[
helloyou2012](https://github.com/helloyou2012)
|[
maxming2333](https://github.com/maxming2333)
- -This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Sun Feb 12 2023 17:38:47 GMT+0800`. +[![Contributors](https://contrib.rocks/image?repo=eggjs/static)](https://github.com/eggjs/static/graphs/contributors) - +Made with [contributors-img](https://contrib.rocks). diff --git a/app.js b/app.js deleted file mode 100644 index 51d51fa..0000000 --- a/app.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -module.exports = app => { - const index = app.config.coreMiddleware.indexOf('bodyParser'); - /* istanbul ignore next */ - if (index === -1) { - app.config.coreMiddleware.push('static'); - } else { - app.config.coreMiddleware.splice(index, 0, 'static'); - } -}; diff --git a/app/middleware/static.js b/app/middleware/static.js deleted file mode 100644 index 2ff0733..0000000 --- a/app/middleware/static.js +++ /dev/null @@ -1,57 +0,0 @@ -const assert = require('assert'); -const { mkdirSync, existsSync } = require('fs'); -const range = require('koa-range'); -const compose = require('koa-compose'); -const staticCache = require('koa-static-cache'); -const LRU = require('ylru'); -const is = require('is-type-of'); - -module.exports = (options, app) => { - const dirs = (options.dirs || []).concat(options.dir); - - const prefixs = []; - - function rangeMiddleware(ctx, next) { - // if match static file, and use range middleware. - const isMatch = prefixs.some(p => ctx.path.startsWith(p)); - if (isMatch) { - return range(ctx, next); - } - return next(); - } - - const middlewares = [ rangeMiddleware ]; - - for (const dirObj of dirs) { - assert(is.object(dirObj) || is.string(dirObj), '`config.static.dir` must be `string | Array`.'); - - let newOptions; - - if (is.string(dirObj)) { - // copy origin options to new options ensure the safety of objects - newOptions = Object.assign({}, options, { dir: dirObj }); - } else { - assert(is.string(dirObj.dir), '`config.static.dir` should contains `[].dir` property when object style.'); - newOptions = Object.assign({}, options, dirObj); - } - - if (newOptions.dynamic && !newOptions.files) { - newOptions.files = new LRU(newOptions.maxFiles); - } - - if (newOptions.prefix) { - prefixs.push(newOptions.prefix); - } - - // ensure directory exists - if (!existsSync(newOptions.dir)) { - mkdirSync(newOptions.dir, { recursive: true }); - } - - app.loggers.coreLogger.info('[egg-static] starting static serve %s -> %s', newOptions.prefix, newOptions.dir); - - middlewares.push(staticCache(newOptions)); - } - - return compose(middlewares); -}; diff --git a/config/config.default.js b/config/config.default.js deleted file mode 100644 index 20bc63f..0000000 --- a/config/config.default.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -const path = require('path'); - -module.exports = appInfo => { - const exports = {}; - - /** - * Static file serve - * - * @member Config#static - * @property {String} prefix - `/public/` by default - * @property {String} dir - static files store dir, `${baseDir}/app/public` by default - * @property {Number} maxAge - cache max age, default is 0 - * @see https://github.com/koajs/static-cache - */ - exports.static = { - prefix: '/public/', - dir: path.join(appInfo.baseDir, 'app/public'), - // dirs: [ dir1, dir2 ] or [ dir1, { prefix: '/static2', dir: dir2 } ], - // support lazy load - dynamic: true, - preload: false, - buffer: false, - maxFiles: 1000, - }; - return exports; -}; diff --git a/config/config.prod.js b/config/config.prod.js deleted file mode 100644 index c5bf97d..0000000 --- a/config/config.prod.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -exports.static = { - maxAge: 31536000, - buffer: true, -}; diff --git a/package.json b/package.json index cd04947..fd62965 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,21 @@ { - "name": "egg-static", + "name": "@eggjs/static", "version": "2.3.1", + "publishConfig": { + "access": "public" + }, "description": "static server plugin for egg", "eggPlugin": { - "name": "static" + "name": "static", + "exports": { + "import": "./dist/esm", + "require": "./dist/commonjs", + "typescript": "./src" + } }, - "files": [ - "app", - "config", - "app.js" - ], "repository": { "type": "git", - "url": "git+https://github.com/eggjs/egg-static.git" + "url": "git+https://github.com/eggjs/static.git" }, "keywords": [ "egg", @@ -20,32 +23,71 @@ "eggPlugin", "static" ], + "author": "dead_horse", + "license": "MIT", + "engines": { + "node": ">= 18.19.0" + }, "dependencies": { - "is-type-of": "^1.2.1", + "@eggjs/core": "^6.2.13", + "@eggjs/koa-static-cache": "^6.0.0", + "is-type-of": "^2.2.0", "koa-compose": "^4.1.0", "koa-range": "^0.3.0", - "koa-static-cache": "^5.1.2", - "ylru": "^1.3.2" + "ylru": "^2.0.0" }, "devDependencies": { - "egg": "3", - "egg-bin": "5", - "egg-mock": "5", + "@arethetypeswrong/cli": "^0.17.1", + "@eggjs/bin": "7", + "@eggjs/mock": "^6.0.5", + "@eggjs/tsconfig": "1", + "@types/koa-compose": "^3.2.8", + "@types/koa-range": "^0.3.5", + "@types/mocha": "10", + "@types/node": "22", + "egg": "4", "eslint": "8", - "eslint-config-egg": "12", - "git-contributor": "2" - }, - "engines": { - "node": ">=14.0.0" + "eslint-config-egg": "14", + "rimraf": "6", + "tshy": "3", + "tshy-after": "1", + "typescript": "5" }, "scripts": { - "lint": "eslint .", - "test": "npm run lint -- --fix && npm run test-local", - "test-local": "egg-bin test", - "cov": "egg-bin cov", - "ci": "npm run lint && npm run cov", - "contributor": "git-contributor" + "lint": "eslint --cache src test --ext .ts", + "pretest": "npm run clean && npm run lint -- --fix", + "test": "egg-bin test", + "preci": "npm run clean && npm run lint", + "ci": "egg-bin cov", + "postci": "npm run prepublishOnly && npm run clean", + "clean": "rimraf dist", + "prepublishOnly": "tshy && tshy-after && attw --pack" }, - "author": "dead_horse", - "license": "MIT" + "type": "module", + "tshy": { + "exports": { + ".": "./src/index.ts", + "./package.json": "./package.json" + } + }, + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/commonjs/index.d.ts", + "default": "./dist/commonjs/index.js" + } + }, + "./package.json": "./package.json" + }, + "files": [ + "dist", + "src" + ], + "types": "./dist/commonjs/index.d.ts", + "main": "./dist/commonjs/index.js", + "module": "./dist/esm/index.js" } diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..24caf7c --- /dev/null +++ b/src/app.ts @@ -0,0 +1,18 @@ +import type { ILifecycleBoot, EggCore } from '@eggjs/core'; + +export default class AppBoot implements ILifecycleBoot { + private readonly app; + constructor(app: EggCore) { + this.app = app; + } + async configWillLoad() { + const app = this.app; + // make sure static middleware is before bodyParser + const index = app.config.coreMiddleware.indexOf('bodyParser'); + if (index === -1) { + app.config.coreMiddleware.push('static'); + } else { + app.config.coreMiddleware.splice(index, 0, 'static'); + } + } +} diff --git a/src/app/middleware/static.ts b/src/app/middleware/static.ts new file mode 100644 index 0000000..3e33418 --- /dev/null +++ b/src/app/middleware/static.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert'; +import { mkdirSync, existsSync } from 'node:fs'; +import range from 'koa-range'; +import compose from 'koa-compose'; +import type { EggCore, Context, Next } from '@eggjs/core'; +import { staticCache } from '@eggjs/koa-static-cache'; +import { LRU } from 'ylru'; +import { isObject } from 'is-type-of'; +import type { StaticConfig, StaticDirOptions } from '../../types.js'; + +export default (options: StaticConfig, app: EggCore) => { + const dirs = (options.dirs ?? []).concat(options.dir); + + const prefixes: string[] = []; + + function rangeMiddleware(ctx: Context, next: Next) { + // if match static file, and use range middleware. + const isMatch = prefixes.some(p => ctx.path.startsWith(p)); + if (isMatch) { + return range(ctx as any, next); + } + return next(); + } + + const middlewares = [ rangeMiddleware ]; + + for (const dirObj of dirs) { + assert(isObject(dirObj) || typeof dirObj === 'string', + '`config.static.dir` must be `string | Array`'); + + let newOptions: StaticDirOptions; + if (typeof dirObj === 'string') { + // copy origin options to new options ensure the safety of objects + newOptions = { + ...options, + dir: dirObj, + }; + } else { + assert(typeof dirObj.dir === 'string', + '`config.static.dirs` should contains `[].dir` property when object style'); + newOptions = { + ...options, + ...dirObj, + }; + } + + if (newOptions.dynamic && !newOptions.files) { + newOptions.files = new LRU(newOptions.maxFiles); + } + + if (newOptions.prefix) { + prefixes.push(newOptions.prefix); + } + + // ensure directory exists + if (!existsSync(newOptions.dir)) { + mkdirSync(newOptions.dir, { recursive: true }); + } + middlewares.push(staticCache(newOptions)); + + (app as any).coreLogger.info('[@eggjs/static] starting static serve %s -> %s', + newOptions.prefix, newOptions.dir); + } + + return compose(middlewares); +}; diff --git a/src/config/config.default.ts b/src/config/config.default.ts new file mode 100644 index 0000000..4834b70 --- /dev/null +++ b/src/config/config.default.ts @@ -0,0 +1,19 @@ +import path from 'node:path'; +import type { EggAppInfo } from '@eggjs/core'; +import type { StaticConfig } from '../types.js'; + +export default (appInfo: EggAppInfo) => { + return { + static: { + prefix: '/public/', + dir: path.join(appInfo.baseDir, 'app/public'), + // dirs: [ dir1, dir2 ] or [ dir1, { prefix: '/static2', dir: dir2 } ], + dirs: undefined, + // support lazy load + dynamic: true, + preload: false, + buffer: false, + maxFiles: 1000, + } as StaticConfig, + }; +}; diff --git a/src/config/config.prod.ts b/src/config/config.prod.ts new file mode 100644 index 0000000..df6b1f3 --- /dev/null +++ b/src/config/config.prod.ts @@ -0,0 +1,8 @@ +import type { StaticConfig } from '../types.js'; + +export default { + static: { + maxAge: 31536000, + buffer: true, + } as StaticConfig, +}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ce5fb25 --- /dev/null +++ b/src/index.ts @@ -0,0 +1 @@ +import './types.js'; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..e46ba0a --- /dev/null +++ b/src/types.ts @@ -0,0 +1,64 @@ +import type { Options as StaticCacheOptions } from '@eggjs/koa-static-cache'; + +export interface StaticDirOptions extends Omit { + /** + * static files store dir + */ + dir: string; + /** + * static files prefix + * Default to `'/public/'` + */ + prefix: string; + /** + * cache max age in `seconds` + * Default to `0` on development, `31536000` on production + */ + maxAge: number; + /** + * dynamic load file which not cached on initialization + * Default to `true + */ + dynamic: boolean; + /** + * caches the assets on initialization or not, + * always work together with `options.dynamic` + * Default to `false` + */ + preload: boolean; + /** + * buffer the file content or not + * Default to `false` on development, `true` on production + */ + buffer: boolean; + /** + * max files count in store + * Default to `1000` + */ + maxFiles: number; +} + +/** + * Static file serve + * @member Config#static + * @see https://github.com/koajs/static-cache + */ +export interface StaticConfig extends Omit { + /** + * static files store dir + * Default to `${baseDir}/app/public` + */ + dir: string | Array; + /** + * static files store dirs + * @deprecated use `dir` instead + */ + dirs?: Array; +} + +declare module '@eggjs/core' { + // add EggAppConfig overrides types + interface EggAppConfig { + static: StaticConfig; + } +} diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts new file mode 100644 index 0000000..53c65c7 --- /dev/null +++ b/src/typings/index.d.ts @@ -0,0 +1,4 @@ +// make sure to import egg typings and let typescript know about it +// @see https://github.com/whxaxes/blog/issues/11 +// and https://www.typescriptlang.org/docs/handbook/declaration-merging.html +import 'egg'; diff --git a/test/static.test.js b/test/static.test.ts similarity index 82% rename from test/static.test.js rename to test/static.test.ts index 30cb368..e651eb1 100644 --- a/test/static.test.js +++ b/test/static.test.ts @@ -1,10 +1,18 @@ -const path = require('path'); -const fs = require('fs/promises'); -const mock = require('egg-mock'); +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import fs from 'node:fs/promises'; +import { mock, MockApplication } from '@eggjs/mock'; -describe('test/static.test.js', () => { +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export function getFixtures(filename: string) { + return path.join(__dirname, 'fixtures', filename); +} + +describe('test/static.test.ts', () => { describe('serve public', () => { - let app; + let app: MockApplication; before(() => { app = mock.app({ baseDir: 'static-server', @@ -39,7 +47,8 @@ describe('test/static.test.js', () => { .set('range', 'bytes=0-10') .expect('Content-Length', '11') .expect('Accept-Ranges', 'bytes') - .expect('Content-Range', 'bytes 0-10/20') + .expect('Content-Range', + process.platform === 'win32' ? 'bytes 0-10/21' : 'bytes 0-10/20') .expect('console.log') .expect(206); }); @@ -54,8 +63,8 @@ describe('test/static.test.js', () => { }); describe('serve dist', () => { - let app; - const jsFile = path.join(__dirname, 'fixtures/static-server-dist/dist/static/app/a.js'); + let app: MockApplication; + const jsFile: string = getFixtures('static-server-dist/dist/static/app/a.js'); before(async () => { await fs.writeFile(jsFile, 'console.log(\'a\')'); app = mock.app({ @@ -88,7 +97,7 @@ describe('test/static.test.js', () => { }); describe('serve custom using config.js', () => { - let app; + let app: MockApplication; before(() => { app = mock.app({ baseDir: 'static-server-custom', @@ -107,8 +116,8 @@ describe('test/static.test.js', () => { }); describe('serve multiple folder with options.dir', () => { - let app; - const jsFile = path.join(__dirname, 'fixtures/static-server-with-dir/dist/static/app/a.js'); + let app: MockApplication; + const jsFile = getFixtures('static-server-with-dir/dist/static/app/a.js'); before(async () => { await fs.writeFile(jsFile, 'console.log(\'a\')'); app = mock.app({ @@ -133,7 +142,9 @@ describe('test/static.test.js', () => { .set('range', 'bytes=0-10') .expect('Content-Length', '11') .expect('Accept-Ranges', 'bytes') - .expect('Content-Range', 'bytes 0-10/20') + .expect('Content-Range', + process.platform === 'win32' ? 'bytes 0-10/21' : 'bytes 0-10/20', + ) .expect('console.log') .expect(206); }); @@ -159,8 +170,8 @@ describe('test/static.test.js', () => { }); describe('serve multiple folder with options.dirs', () => { - let app; - const jsFile = path.join(__dirname, 'fixtures/static-server-with-dirs/dist/static/app/a.js'); + let app: MockApplication; + const jsFile = getFixtures('static-server-with-dirs/dist/static/app/a.js'); before(async () => { await fs.writeFile(jsFile, 'console.log(\'a\')'); app = mock.app({ @@ -185,7 +196,9 @@ describe('test/static.test.js', () => { .set('range', 'bytes=0-10') .expect('Content-Length', '11') .expect('Accept-Ranges', 'bytes') - .expect('Content-Range', 'bytes 0-10/20') + .expect('Content-Range', + process.platform === 'win32' ? 'bytes 0-10/21' : 'bytes 0-10/20', + ) .expect('console.log') .expect(206); }); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..ff41b73 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@eggjs/tsconfig", + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext" + } +}