diff --git a/packages/docz-core/package.json b/packages/docz-core/package.json index 6e87eec02..9ba814541 100644 --- a/packages/docz-core/package.json +++ b/packages/docz-core/package.json @@ -51,6 +51,7 @@ "hast-util-to-string": "^1.0.1", "html-webpack-plugin": "^3.2.0", "humanize-string": "^1.0.2", + "koa": "^2.5.2", "koa-connect": "^2.0.1", "koa-mount": "^3.0.0", "koa-static": "^5.0.0", @@ -98,6 +99,7 @@ "@types/express": "^4.16.0", "@types/fs-extra": "^5.0.4", "@types/html-webpack-plugin": "^2.30.4", + "@types/koa": "^2.0.46", "@types/lodash.get": "^4.4.3", "@types/node": "10.5.2", "@types/prettier": "^1.13.2", diff --git a/packages/docz-core/src/Bundler.ts b/packages/docz-core/src/Bundler.ts index 41d85dd71..66f4d25d3 100644 --- a/packages/docz-core/src/Bundler.ts +++ b/packages/docz-core/src/Bundler.ts @@ -10,14 +10,21 @@ export interface Server { close: () => void } +export interface ServerHooks { + onCreateApp(app: A): void + OnServerListening(server: S): void +} + export interface BundlerServer { start(): Promise } export type ConfigFn = (babelrc: BabelRC) => C -export type ServerFn = (config: C) => BundlerServer | Promise export type BuildFn = (config: C, dist: string) => void +export type ServerFnReturn = BundlerServer | Promise +export type ServerFn = (config: C, hooks: ServerHooks) => ServerFnReturn + export interface BundlerConstructor { args: Args config: ConfigFn @@ -52,7 +59,17 @@ export class Bundler { } public async createServer(config: C): Promise { - return this.server(config) + const run = Plugin.runPluginsMethod(this.args.plugins) + const hooks = { + onCreateApp(app: A): void { + run('onCreateApp', app) + }, + OnServerListening(server: S): void { + run('onServerListening', server) + }, + } + + return this.server(config, hooks) } public async build(config: C): Promise { diff --git a/packages/docz-core/src/Plugin.ts b/packages/docz-core/src/Plugin.ts index 52ad42233..af7c62db1 100644 --- a/packages/docz-core/src/Plugin.ts +++ b/packages/docz-core/src/Plugin.ts @@ -11,6 +11,7 @@ export type ModifyBundlerConfig = ( args: Config ) => C export type ModifyBabelRC = (babelrc: BabelRC, args: Config) => BabelRC +export type onCreateApp = (app: A) => void export type OnServerListening = (server: S) => void export type OnPreBuild = () => void export type OnPostBuild = () => void @@ -21,6 +22,7 @@ export interface PluginFactory { setConfig?: SetConfig modifyBundlerConfig?: ModifyBundlerConfig modifyBabelRc?: ModifyBabelRC + onCreateApp?: onCreateApp onServerListening?: OnServerListening onPreBuild?: OnPreBuild onPostBuild?: OnPostBuild @@ -65,6 +67,7 @@ export class Plugin implements PluginFactory { public readonly setConfig?: SetConfig public readonly modifyBundlerConfig?: ModifyBundlerConfig public readonly modifyBabelRc?: ModifyBabelRC + public readonly onCreateApp?: onCreateApp public readonly onServerListening?: OnServerListening public readonly onPreBuild?: OnPreBuild public readonly onPostBuild?: OnPostBuild @@ -75,6 +78,7 @@ export class Plugin implements PluginFactory { this.setConfig = p.setConfig this.modifyBundlerConfig = p.modifyBundlerConfig this.modifyBabelRc = p.modifyBabelRc + this.onCreateApp = p.onCreateApp this.onServerListening = p.onServerListening this.onPreBuild = p.onPreBuild this.onPostBuild = p.onPostBuild diff --git a/packages/docz-core/src/bundlers/webpack/devserver.ts b/packages/docz-core/src/bundlers/webpack/devserver.ts index 861c0263d..567a117f6 100644 --- a/packages/docz-core/src/bundlers/webpack/devserver.ts +++ b/packages/docz-core/src/bundlers/webpack/devserver.ts @@ -1,12 +1,18 @@ import * as path from 'path' +import * as Koa from 'koa' import { Configuration } from 'webpack' import convert from 'koa-connect' import history from 'connect-history-api-fallback' import serveWaitpage from 'webpack-serve-waitpage' import { Config } from '../../commands/args' +import { ServerHooks } from '../../Bundler' -export const devServerConfig = (args: Config, config: Configuration) => { +export const devServerConfig = ( + args: Config, + config: Configuration, + hooks: ServerHooks +) => { const nonExistentDir = path.resolve(__dirname, 'non-existent') const logLevel = (level: string) => (args.debug ? 'debug' : level) @@ -23,7 +29,10 @@ export const devServerConfig = (args: Config, config: Configuration) => { reload: false, logLevel: logLevel('error'), }, - add: (app: any, middleware: any, options: any) => { + add: (app: Koa, middleware: any, options: any) => { + middleware.webpack() + middleware.content() + app.use( convert( history({ @@ -33,6 +42,7 @@ export const devServerConfig = (args: Config, config: Configuration) => { ) app.use(serveWaitpage(options, { title: args.title })) + hooks.onCreateApp(app) }, } } diff --git a/packages/docz-core/src/bundlers/webpack/server.ts b/packages/docz-core/src/bundlers/webpack/server.ts index d6a7c0061..92f4682cc 100644 --- a/packages/docz-core/src/bundlers/webpack/server.ts +++ b/packages/docz-core/src/bundlers/webpack/server.ts @@ -2,17 +2,22 @@ import { Configuration as Config } from 'webpack' import serve from 'webpack-serve' import { devServerConfig } from './devserver' -import { BundlerServer } from '../../Bundler' +import { BundlerServer, ServerHooks } from '../../Bundler' import { Config as Args } from '../../commands/args' +import * as http from 'http' type Server = Promise -export const server = (args: Args) => async (config: Config): Server => { - const devserver = devServerConfig(args, config) +export const server = (args: Args) => async ( + config: Config, + hooks: ServerHooks +): Server => { + const devserver = devServerConfig(args, config, hooks) return { start: async () => { const instance = await serve({}, devserver) + hooks.OnServerListening(instance.app.server) return { ...instance, diff --git a/packages/docz-core/src/commands/dev.ts b/packages/docz-core/src/commands/dev.ts index 27a07529f..be6315511 100644 --- a/packages/docz-core/src/commands/dev.ts +++ b/packages/docz-core/src/commands/dev.ts @@ -10,7 +10,6 @@ import { Config, Env } from './args' import { DataServer } from '../DataServer' import { webpack } from '../bundlers' import { Entries } from '../Entries' -import { Plugin } from '../Plugin' import { loadConfig } from '../utils/load-config' const env = process.env.NODE_ENV as Env @@ -25,7 +24,6 @@ export const dev = async (args: Config) => { const server = await bundler.createServer(bundler.getConfig(env)) const { app } = await server.start() - const run = Plugin.runPluginsMethod(config.plugins) const newConfig = { ...config, websocketPort } const dataServer = new DataServer({ server: app.server, @@ -43,7 +41,6 @@ export const dev = async (args: Config) => { logger.info(`Setup entries websockets server on port ${websocketPort}`) await dataServer.processEntries(entries) await dataServer.processThemeConfig() - await run('onServerListening', server) } catch (err) { logger.fatal('Failed to process your server:', err) process.exit(1) diff --git a/yarn.lock b/yarn.lock index f61298feb..e6fc9d994 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1190,6 +1190,12 @@ escape-string-regexp "^1.0.5" lodash.deburr "^4.1.0" +"@types/accepts@*": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz#c34bec115cfc746e04fe5a059df4ce7e7b391575" + dependencies: + "@types/node" "*" + "@types/bluebird@^3.5.22": version "3.5.22" resolved "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.22.tgz#519b87fe3c9d290ca6c06381ffc3040770ab452b" @@ -1231,6 +1237,15 @@ dependencies: "@types/node" "*" +"@types/cookies@*": + version "0.7.1" + resolved "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.1.tgz#f9f204bd6767d389eea3b87609e30c090c77a540" + dependencies: + "@types/connect" "*" + "@types/express" "*" + "@types/keygrip" "*" + "@types/node" "*" + "@types/deepmerge@^2.1.0": version "2.1.0" resolved "https://registry.npmjs.org/@types/deepmerge/-/deepmerge-2.1.0.tgz#22f175e5cb55874fe818caa6fd50a1d98fc3d748" @@ -1256,7 +1271,7 @@ "@types/events" "*" "@types/node" "*" -"@types/express@^4.16.0": +"@types/express@*", "@types/express@^4.16.0": version "4.16.0" resolved "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz#6d8bc42ccaa6f35cf29a2b7c3333cb47b5a32a19" dependencies: @@ -1302,6 +1317,30 @@ "@types/tapable" "*" "@types/webpack" "*" +"@types/http-assert@*": + version "1.3.0" + resolved "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.3.0.tgz#5e932606153da28e1d04f9043f4912cf61fd55dd" + +"@types/keygrip@*": + version "1.0.1" + resolved "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.1.tgz#ff540462d2fb4d0a88441ceaf27d287b01c3d878" + +"@types/koa-compose@*": + version "3.2.2" + resolved "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.2.tgz#dc106e000bbf92a3ac900f756df47344887ee847" + +"@types/koa@^2.0.46": + version "2.0.46" + resolved "https://registry.npmjs.org/@types/koa/-/koa-2.0.46.tgz#24bc3cd405d10fcde81f876cd8285b44d4ddc3e9" + dependencies: + "@types/accepts" "*" + "@types/cookies" "*" + "@types/events" "*" + "@types/http-assert" "*" + "@types/keygrip" "*" + "@types/koa-compose" "*" + "@types/node" "*" + "@types/lodash.get@^4.4.3": version "4.4.3" resolved "https://registry.npmjs.org/@types/lodash.get/-/lodash.get-4.4.3.tgz#ac823d175a9593c10555b5097b72281effd544b5" @@ -1615,7 +1654,7 @@ abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -accepts@^1.2.2, accepts@~1.3.5: +accepts@^1.2.2, accepts@^1.3.5, accepts@~1.3.5: version "1.3.5" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: @@ -3021,6 +3060,13 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cache-content-type@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" + dependencies: + mime-types "^2.1.18" + ylru "^1.2.0" + cachedir@^1.1.0: version "1.3.0" resolved "https://registry.npmjs.org/cachedir/-/cachedir-1.3.0.tgz#5e01928bf2d95b5edd94b0942188246740e0dbc4" @@ -3571,11 +3617,11 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" -content-disposition@0.5.2, content-disposition@~0.5.0: +content-disposition@0.5.2, content-disposition@~0.5.0, content-disposition@~0.5.2: version "0.5.2" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type@^1.0.0, content-type@~1.0.4: +content-type@^1.0.0, content-type@^1.0.4, content-type@~1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -3745,7 +3791,7 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" -cookies@~0.7.0: +cookies@~0.7.0, cookies@~0.7.1: version "0.7.1" resolved "https://registry.npmjs.org/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" dependencies: @@ -4324,7 +4370,7 @@ depd@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" -depd@^1.1.0, depd@~1.1.1, depd@~1.1.2: +depd@^1.1.0, depd@^1.1.2, depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -4335,7 +4381,7 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@^1.0.3, destroy@~1.0.4: +destroy@^1.0.3, destroy@^1.0.4, destroy@~1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -4606,7 +4652,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error-inject@~1.0.0: +error-inject@^1.0.0, error-inject@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" @@ -4677,7 +4723,7 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.1: d "1" es5-ext "~0.10.14" -escape-html@~1.0.1, escape-html@~1.0.3: +escape-html@^1.0.3, escape-html@~1.0.1, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -5328,7 +5374,7 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fresh@0.5.2, fresh@^0.5.2: +fresh@0.5.2, fresh@^0.5.2, fresh@~0.5.2: version "0.5.2" resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -6063,7 +6109,7 @@ htmlparser2@~3.3.0: domutils "1.1" readable-stream "1.0" -http-assert@^1.1.0: +http-assert@^1.1.0, http-assert@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" dependencies: @@ -6510,7 +6556,7 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-generator-function@^1.0.3: +is-generator-function@^1.0.3, is-generator-function@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" @@ -6920,6 +6966,10 @@ koa-compose@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/koa-compose/-/koa-compose-4.0.0.tgz#2800a513d9c361ef0d63852b038e4f6f2d5a773c" +koa-compose@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + koa-connect@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/koa-connect/-/koa-connect-2.0.1.tgz#2acad159c33862de1d73aa4562a48de13f137c0f" @@ -6999,6 +7049,35 @@ koa@^2.4.1: type-is "^1.5.5" vary "^1.0.0" +koa@^2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/koa/-/koa-2.5.2.tgz#f2bda7f3e70be54924e7e5e9789a249f77256fe3" + dependencies: + accepts "^1.3.5" + cache-content-type "^1.0.0" + content-disposition "~0.5.2" + content-type "^1.0.4" + cookies "~0.7.1" + debug "^3.1.0" + delegates "^1.0.0" + depd "^1.1.2" + destroy "^1.0.4" + error-inject "^1.0.0" + escape-html "^1.0.3" + fresh "~0.5.2" + http-assert "^1.3.0" + http-errors "^1.6.3" + is-generator-function "^1.0.7" + koa-compose "^4.1.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + on-finished "^2.3.0" + only "~0.0.2" + parseurl "^1.3.2" + statuses "^1.5.0" + type-is "^1.6.16" + vary "^1.1.2" + last-call-webpack-plugin@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" @@ -7783,12 +7862,22 @@ mime-db@~1.33.0: version "1.33.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + mime-types@^2.0.7, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.7: version "2.1.18" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" dependencies: mime-db "~1.33.0" +mime-types@^2.1.18: + version "2.1.19" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + mime@1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" @@ -8400,7 +8489,7 @@ object.values@^1.0.4: function-bind "^1.1.0" has "^1.0.1" -on-finished@^2.1.0, on-finished@~2.3.0: +on-finished@^2.1.0, on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: @@ -8422,7 +8511,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -only@0.0.2: +only@0.0.2, only@~0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" @@ -8712,7 +8801,7 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parseurl@^1.3.0, parseurl@~1.3.2: +parseurl@^1.3.0, parseurl@^1.3.2, parseurl@~1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" @@ -10748,7 +10837,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", statuses@^1.2.0: +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2", statuses@^1.2.0, statuses@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -11363,7 +11452,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@^1.5.5, type-is@~1.6.15, type-is@~1.6.16: +type-is@^1.5.5, type-is@^1.6.16, type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: @@ -11817,7 +11906,7 @@ value-equal@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" -vary@^1.0.0, vary@~1.1.2: +vary@^1.0.0, vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -12415,3 +12504,7 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +ylru@^1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f"