diff --git a/packages/api/src/app.ts b/packages/api/src/app.ts index fb7ff8ef3..40a28a651 100644 --- a/packages/api/src/app.ts +++ b/packages/api/src/app.ts @@ -1,4 +1,4 @@ -import Api from '@nocobase/server'; +import Server from '@nocobase/server'; // @ts-ignore const sync = global.sync || { @@ -10,14 +10,14 @@ const sync = global.sync || { console.log('process.env.NOCOBASE_ENV', process.env.NOCOBASE_ENV); -const api = Api.create({ +const api = new Server({ database: { username: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, host: process.env.DB_HOST, - port: process.env.DB_PORT, - dialect: process.env.DB_DIALECT, + port: process.env.DB_PORT as any, + dialect: process.env.DB_DIALECT as any, dialectOptions: { charset: 'utf8mb4', collate: 'utf8mb4_unicode_ci', @@ -25,7 +25,7 @@ const api = Api.create({ pool: { max: 5, min: 0, - acquire: 30000, + acquire: 60000, idle: 10000, }, logging: process.env.DB_LOG_SQL === 'on' ? console.log : false, @@ -47,7 +47,7 @@ const plugins = [ '@nocobase/plugin-permissions', '@nocobase/plugin-export', '@nocobase/plugin-system-settings', - // '@nocobase/plugin-automations', + // // '@nocobase/plugin-automations', '@nocobase/plugin-china-region', ]; diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index d9ea9e6e7..e4fb81c4b 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -18,7 +18,12 @@ import { middlewares } from '@nocobase/server'; }); const start = Date.now(); - await api.start(process.env.API_PORT); + + if (process.argv.length < 3) { + process.argv.push('start', '--port', process.env.API_PORT); + } + + await api.start(process.argv); console.log(api.database.getTables().map(t => t.getName())); console.log(`Start-up time: ${(Date.now() - start) / 1000}s`); console.log(`http://localhost:${process.env.API_PORT}/`); diff --git a/packages/app/nodemon.json b/packages/app/nodemon.json new file mode 100644 index 000000000..2bbaa3ddb --- /dev/null +++ b/packages/app/nodemon.json @@ -0,0 +1,5 @@ +{ + "watch": ["src/api/", ".env"], + "ext": "ts", + "exec": "cross-env TS_NODE_PROJECT=\"tsconfig.api.json\" ts-node -r dotenv/config ./src/api/index.ts" +} diff --git a/packages/app/package.json b/packages/app/package.json index 1b6383bf0..df33268be 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -4,7 +4,11 @@ "scripts": { "start": "concurrently \"cd ../../ && nodemon\" \"umi dev\"", "start-client": "umi dev", - "build": "umi build", + "start-server": "nodemon", + "build": "npm run build-server && npm run build-client", + "build-client": "umi build", + "nocobase": "cross-env TS_NODE_PROJECT=\"tsconfig.api.json\" ts-node ./src/api/index.ts", + "build-server": "rimraf -rf lib && tsc --project tsconfig.api.json", "postinstall": "umi generate tmp", "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'", "test": "umi-test", @@ -31,10 +35,13 @@ "@types/react-dom": "^17.0.0", "@umijs/test": "^3.4.15", "concurrently": "^5.3.0", + "cross-env": "^7.0.3", "mockjs": "^1.1.0", + "nodemon": "^2.0.12", "prettier": "^2.2.0", "react": "17.x", "react-dom": "17.x", + "ts-node": "^10.2.1", "yorkie": "^2.0.0" } } diff --git a/packages/app/src/api/index.ts b/packages/app/src/api/index.ts new file mode 100644 index 000000000..9d7f34538 --- /dev/null +++ b/packages/app/src/api/index.ts @@ -0,0 +1,71 @@ +import Server from '@nocobase/server'; +import dotenv from 'dotenv'; +import path from 'path'; + +const start = Date.now(); +console.log('startAt', new Date().toUTCString()); + +dotenv.config({ + path: path.resolve(__dirname, '../../../../.env'), +}); + +const api = new Server({ + database: { + username: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_DATABASE, + host: process.env.DB_HOST, + port: process.env.DB_PORT as any, + dialect: process.env.DB_DIALECT as any, + dialectOptions: { + charset: 'utf8mb4', + collate: 'utf8mb4_unicode_ci', + }, + pool: { + max: 5, + min: 0, + acquire: 60000, + idle: 10000, + }, + logging: process.env.DB_LOG_SQL === 'on' ? console.log : false, + define: {}, + sync: { + force: false, + alter: { + drop: false, + }, + }, + }, + resourcer: { + prefix: '/api', + }, +}); + +const plugins = [ + '@nocobase/plugin-collections', + '@nocobase/plugin-ui-router', + '@nocobase/plugin-ui-schema', + '@nocobase/plugin-users', + '@nocobase/plugin-action-logs', + '@nocobase/plugin-file-manager', + '@nocobase/plugin-permissions', + '@nocobase/plugin-export', + '@nocobase/plugin-system-settings', + // '@nocobase/plugin-automations', + '@nocobase/plugin-china-region', +]; + +for (const plugin of plugins) { + api.registerPlugin(plugin, [ + require(`${plugin}/${__filename.endsWith('.ts') ? 'src' : 'lib'}/server`) + .default, + ]); +} + +if (process.argv.length < 3) { + process.argv.push('start', '--port', '2000'); +} + +api.start(process.argv).then(() => { + console.log(`Start-up time: ${(Date.now() - start) / 1000}s`); +}); diff --git a/packages/app/tsconfig.api.json b/packages/app/tsconfig.api.json new file mode 100644 index 000000000..4b14009ec --- /dev/null +++ b/packages/app/tsconfig.api.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./lib/api" + }, + "include": [ + "src/api", + ] +} \ No newline at end of file diff --git a/packages/server/package.json b/packages/server/package.json index e8202388d..64ee55b03 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -11,6 +11,7 @@ "@nocobase/actions": "^0.4.0-alpha.7", "@nocobase/database": "^0.4.0-alpha.7", "@nocobase/resourcer": "^0.4.0-alpha.7", + "commander": "^8.1.0", "dotenv": "^8.2.0", "koa": "^2.13.0", "koa-bodyparser": "^4.3.0", diff --git a/packages/server/src/application.ts b/packages/server/src/application.ts index 7326ca202..37bfcbcc3 100644 --- a/packages/server/src/application.ts +++ b/packages/server/src/application.ts @@ -1,6 +1,11 @@ import Koa from 'koa'; import Database, { DatabaseOptions } from '@nocobase/database'; import Resourcer from '@nocobase/resourcer'; +import { Command } from 'commander'; +import { actions, middlewares as m } from '@nocobase/actions'; +import cors from '@koa/cors'; +import { dbResourceRouter } from './middlewares'; +import bodyParser from 'koa-bodyparser'; export interface ApplicationOptions { database: DatabaseOptions; @@ -8,19 +13,73 @@ export interface ApplicationOptions { } export class Application extends Koa { - // static const EVENT_PLUGINS_LOADED = Symbol('pluginsLoaded'); public readonly database: Database; public readonly resourcer: Resourcer; + public readonly cli: Command; + protected plugins = new Map(); constructor(options: ApplicationOptions) { super(); this.database = new Database(options.database); this.resourcer = new Resourcer(); - // this.runHook('afterInit'); + this.cli = new Command(); + + this.use(bodyParser()); + this.use(cors({ + exposeHeaders: ['content-disposition'], + })); + + this.resourcer.registerActionHandlers({ ...actions.common, ...actions.associate }); + + this.use(async (ctx, next) => { + ctx.db = this.database; + ctx.database = this.database; + await next(); + }); + + this.resourcer.use(m.associated); + this.use(m.dataWrapping); + + this.use(dbResourceRouter({ + database: this.database, + resourcer: this.resourcer, + ...(options.resourcer || {}), + })); + + this.cli + .command('db sync') + .option('-f, --force') + .action(async (...args) => { + const cli = args.pop(); + await this.database.sync(); + await this.database.close(); + }); + + this.cli + .command('db init') + // .option('-f, --force') + .action(async (...args) => { + const cli = args.pop(); + await this.emitAsync('db.init'); + await this.database.close(); + }); + + this.cli + .command('start') + .option('-p, --port [port]') + .action(async (...args) => { + const cli = args.pop(); + console.log(args); + const opts = cli.opts(); + await this.loadPlugins(); + await this.emitAsync('server.beforeStart'); + this.listen(opts.port || 3000); + console.log(`http://localhost:${opts.port || 3000}/`); + }); } async emitAsync(event: string | symbol, ...args: any[]): Promise { @@ -108,10 +167,8 @@ export class Application extends Koa { await this.emitAsync('plugins.afterLoad'); } - async start(port) { - await this.loadPlugins(); - await this.emitAsync('server.beforeStart'); - this.listen(port); + async start(argv = process.argv) { + return this.cli.parseAsync(argv); } protected async loadPlugin({ entry, options = {} }: { entry: string | Function, options: any }) { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 5bf71159c..83658ceac 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1,46 +1,3 @@ -import { actions, middlewares as m } from '@nocobase/actions'; -import Application from './application'; -import bodyParser from 'koa-bodyparser'; -import cors from '@koa/cors'; -import { dbResourceRouter } from './middlewares'; - export * from './application'; -export * from './middleware'; export * as middlewares from './middlewares'; - -export default { - /** - * 这部分还比较杂,细节待改进 - * - * @param options - */ - create(options: any): Application { - console.log(options); - - const app = new Application(options); - - app.use(bodyParser()); - app.use(cors({ - exposeHeaders: ['content-disposition'], - })); - - app.resourcer.registerActionHandlers({ ...actions.common, ...actions.associate }); - - app.use(async (ctx, next) => { - ctx.db = app.database; - ctx.database = app.database; - await next(); - }); - - app.resourcer.use(m.associated); - app.use(m.dataWrapping); - - app.use(dbResourceRouter({ - database: app.database, - resourcer: app.resourcer, - ...(options.resourcer||{}), - })); - - return app; - } -} +export { Application as default } from './application'; diff --git a/yarn.lock b/yarn.lock index e53871d51..90f958d05 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1745,6 +1745,18 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" + integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" @@ -3512,6 +3524,26 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + "@types/accepts@*": version "1.3.5" resolved "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" @@ -4562,6 +4594,11 @@ acorn-walk@^7.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== +acorn-walk@^8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.1.1.tgz#3ddab7f84e4a7e2313f6c414c5b7dac85f4e3ebc" + integrity sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w== + acorn@5.X, acorn@^5.0.3, acorn@^5.5.3: version "5.7.4" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" @@ -4577,7 +4614,7 @@ acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4: +acorn@^8.2.4, acorn@^8.4.1: version "8.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== @@ -6440,7 +6477,7 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== -commander@*, commander@>=7.0.0: +commander@*, commander@>=7.0.0, commander@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/commander/-/commander-8.1.0.tgz#db36e3e66edf24ff591d639862c6ab2c52664362" integrity sha512-mf45ldcuHSYShkplHHGKWb4TrmwQadxOn7v4WuhDJy0ZVoY5JFajaRDKD0PNe5qXzBX0rhovjTnP6Kz9LETcuA== @@ -6883,6 +6920,13 @@ cron-parser@^3.1.0: is-nan "^1.3.2" luxon "^1.26.0" +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -6903,7 +6947,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.2: +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -7304,6 +7348,11 @@ dayjs@1.x, dayjs@^1.9.1: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz#288b2aa82f2d8418a6c9d4df5898c0737ad02a63" integrity sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw== +debounce@^1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debug-fabulous@1.X: version "1.1.0" resolved "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" @@ -7846,6 +7895,11 @@ dva@^2.6.0-beta.20: react-router-dom "^5.1.2" redux "^4.0.1" +easy-bem@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz#1bfcc10425498090bcfddc0f9c000aba91399e03" + integrity sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -16196,6 +16250,15 @@ react-image-lightbox@^5.1.4: prop-types "^15.7.2" react-modal "^3.11.1" +react-indiana-drag-scroll@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/react-indiana-drag-scroll/-/react-indiana-drag-scroll-2.0.1.tgz#8785488a9e9c789b0e1c092e60d03f05a789d428" + integrity sha512-xZQXfFf9pHLOL6/AvTFiGZCB4Vu8wO8DjEaO+xRVkSki2bEZSFfS8eeKG0OkTzcYVrXzc5aHAD1Mfl3EG+EFMA== + dependencies: + classnames "^2.2.6" + debounce "^1.2.0" + easy-bem "^1.1.1" + react-intl@3.12.1: version "3.12.1" resolved "https://registry.npmjs.org/react-intl/-/react-intl-3.12.1.tgz#e9a783ea20302e9da25e4eda59e5593a43d2ec80" @@ -18889,6 +18952,24 @@ ts-loader@^8.0.7: micromatch "^4.0.0" semver "^7.3.4" +ts-node@^10.2.1: + version "10.2.1" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" + integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== + dependencies: + "@cspotcode/source-map-support" "0.6.1" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + yn "3.1.1" + ts-node@^9.1.1: version "9.1.1" resolved "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"