diff --git a/package-lock.json b/package-lock.json index 814b8abe..a699c08e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -409,9 +409,9 @@ } }, "@dojo/framework": { - "version": "5.0.0-alpha.3", - "resolved": "https://registry.npmjs.org/@dojo/framework/-/framework-5.0.0-alpha.3.tgz", - "integrity": "sha512-n6Cy3t7Zu65ceBM3UfqgBUmyM0F3JGUDIahMhXv4JKkXNaXSaUGuWDdBlRoH3LcEJDk6pj6ZV+J4JYiZ4IyPCQ==", + "version": "5.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@dojo/framework/-/framework-5.0.0-alpha.4.tgz", + "integrity": "sha512-nqF13sk3NtZNWrpRlhc51m+On50w9F0EEqVdSmO2TsFNSS4v40jhE+NYjgwp6V9pKg4GcA07H0mD78VkB1/sdg==", "requires": { "@types/cldrjs": "0.4.20", "@types/globalize": "0.0.34", @@ -590,7 +590,7 @@ "resolved": "https://registry.npmjs.org/@dojo/webpack-contrib/-/webpack-contrib-5.0.0-alpha.7.tgz", "integrity": "sha512-MTMfKZcAnq05uO0VKuo/0OB4RzvcyI0pmR1C+s2Rky/Fc9SKcaKalQp8XgHJSCq1tNEpiEdB+nszhktpK5JlOw==", "requires": { - "@dojo/framework": "^5.0.0-alpha.3", + "@dojo/framework": "^5.0.0-alpha.4", "acorn": "5.3.0", "acorn-dynamic-import": "3.0.0", "bfj-node4": "5.2.0", @@ -2501,9 +2501,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000918", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000918.tgz", - "integrity": "sha512-CAZ9QXGViBvhHnmIHhsTPSWFBujDaelKnUj7wwImbyQRxmXynYqKGi3UaZTSz9MoVh+1EVxOS/DFIkrJYgR3aw==" + "version": "1.0.30000921", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000921.tgz", + "integrity": "sha512-Bu09ciy0lMWLgpYC77I0YGuI8eFRBPPzaSOYJK1jTI64txCphYCqnWbxJYjHABYVt/TYX/p3jNjLBR87u1Bfpw==" }, "capture-stack-trace": { "version": "1.0.1", @@ -3049,6 +3049,11 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=" }, + "connect-inject": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/connect-inject/-/connect-inject-0.4.0.tgz", + "integrity": "sha1-wunrHjd08sVqF8hY+WNnd62x4L4=" + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -4600,9 +4605,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.90", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.90.tgz", - "integrity": "sha512-IjJZKRhFbWSOX1w0sdIXgp4CMRguu6UYcTckyFF/Gjtemsu/25eZ+RXwFlV+UWcIueHyQA1UnRJxocTpH5NdGA==" + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.91.tgz", + "integrity": "sha512-wOWwM4vQpmb97VNkExnwE5e/sUMUb7NXurlEnhE89JOarUp6FOOMKjtTGgj9bmqskZkeRA7u+p0IztJ/y2OP5Q==" }, "elegant-spinner": { "version": "1.0.1", @@ -7188,7 +7193,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { "kind-of": "^3.0.2" @@ -7259,7 +7264,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { "kind-of": "^3.0.2" @@ -14931,9 +14936,9 @@ }, "dependencies": { "@types/node": { - "version": "10.12.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.14.tgz", - "integrity": "sha512-0rVcFRhM93kRGAU88ASCjX9Y3FWDCh+33G5Z5evpKOea4xcpLqDGwmo64+DjgaSezTN5j9KdnUzvxhOw7fNciQ==" + "version": "10.12.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz", + "integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==" }, "@types/webpack": { "version": "4.4.21", diff --git a/package.json b/package.json index c88e962f..bc2595d7 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "cli-columns": "3.1.2", "compression-webpack-plugin": "2.0.0", "connect-history-api-fallback": "1.5.0", + "connect-inject": "0.4.0", "css-loader": "1.0.1", "eventsource-polyfill": "0.9.6", "express": "4.16.2", @@ -144,7 +145,6 @@ "umd-compat-loader": "2.1.1", "webpack": "4.25.1", "webpack-chunk-hash": "0.6.0", - "webpack-dev-middleware": "3.4.0", "webpack-hot-middleware": "2.24.3", "webpack-manifest-plugin": "2.0.4", "webpack-mild-compile": "3.3.1", diff --git a/src/dev.config.ts b/src/dev.config.ts index be7a8106..ecf86e11 100644 --- a/src/dev.config.ts +++ b/src/dev.config.ts @@ -82,7 +82,7 @@ function webpackConfig(args: any): webpack.Configuration { } } - if (args.watch !== 'memory' && args['build-time-render']) { + if (args['build-time-render']) { config.plugins.push( new BuildTimeRender({ ...args['build-time-render'], diff --git a/src/dist.config.ts b/src/dist.config.ts index acba9f5f..26a94c14 100644 --- a/src/dist.config.ts +++ b/src/dist.config.ts @@ -95,7 +95,7 @@ function webpackConfig(args: any): webpack.Configuration { } } - if (args.watch !== 'memory' && args['build-time-render']) { + if (args['build-time-render']) { config.plugins.push( new BuildTimeRender({ ...args['build-time-render'], diff --git a/src/main.ts b/src/main.ts index dc68aadc..1087505e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,7 +22,7 @@ import { moveBuildOptions } from './util/eject'; const fixMultipleWatchTrigger = require('webpack-mild-compile'); const hotMiddleware = require('webpack-hot-middleware'); -const webpackMiddleware = require('webpack-dev-middleware'); +const connectInject = require('connect-inject'); const testModes = ['test', 'unit', 'functional']; @@ -87,8 +87,21 @@ function buildNpmDependencies(): any { } } -function fileWatch(config: webpack.Configuration, args: any): Promise { - const compiler = createWatchCompiler(config); +function fileWatch(config: webpack.Configuration, args: any, app?: express.Application): Promise { + let compiler: webpack.Compiler; + if (args.serve && app) { + const entry = config.entry as any; + const plugins = config.plugins as webpack.Plugin[]; + const timeout = 20 * 1000; + plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin()); + Object.keys(entry).forEach((name) => { + entry[name].unshift('eventsource-polyfill'); + }); + compiler = createWatchCompiler(config); + app.use(hotMiddleware(compiler, { heartbeat: timeout / 2 })); + } else { + compiler = createWatchCompiler(config); + } return new Promise((resolve, reject) => { const watchOptions = config.watchOptions as webpack.Compiler.WatchOptions; @@ -105,43 +118,24 @@ function fileWatch(config: webpack.Configuration, args: any): Promise { }); } -function memoryWatch(config: webpack.Configuration, args: any, app: express.Application): Promise { - const entry = config.entry as any; - const plugins = config.plugins as webpack.Plugin[]; - const timeout = 20 * 1000; - - plugins.push(new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin()); - Object.keys(entry).forEach((name) => { - entry[name].unshift(`webpack-hot-middleware/client?timeout=${timeout}&reload=true`); - entry[name].unshift('eventsource-polyfill'); - }); - - const watchOptions = config.watchOptions as webpack.Compiler.WatchOptions; - const compiler = createWatchCompiler(config); - - compiler.hooks.done.tap('@dojo/cli-build-app', (stats) => { - logger(stats.toJson({ warningsFilter }), config, `Listening on port ${args.port}...`); - }); - - app.use( - webpackMiddleware(compiler, { - logLevel: 'silent', - noInfo: true, - publicPath: '/', - watchOptions - }), - hotMiddleware(compiler, { - heartbeat: timeout / 2 - }) - ); - - return Promise.resolve(); -} - function serve(config: webpack.Configuration, args: any): Promise { let isHttps = false; const app = express(); + app.use( + connectInject({ + rules: [ + { + match: //, + snippet: + "", + fn: (match: string, snippet: string) => { + return snippet + match; + } + } + ] + }) + ); app.use( history({ @@ -169,19 +163,17 @@ function serve(config: webpack.Configuration, args: any): Promise { }) ); - if (args.watch !== 'memory') { - const outputDir = (config.output && config.output.path) || process.cwd(); - if (args.mode === 'dist' && Array.isArray(args.compression)) { - const useBrotli = args.compression.includes('brotli'); - app.use( - expressStaticGzip(outputDir, { - enableBrotli: useBrotli, - orderPreference: useBrotli ? ['br'] : undefined - }) - ); - } else { - app.use(express.static(outputDir)); - } + const outputDir = (config.output && config.output.path) || process.cwd(); + if (args.mode === 'dist' && Array.isArray(args.compression)) { + const useBrotli = args.compression.includes('brotli'); + app.use( + expressStaticGzip(outputDir, { + enableBrotli: useBrotli, + orderPreference: useBrotli ? ['br'] : undefined + }) + ); + } else { + app.use(express.static(outputDir)); } if (args.proxy) { @@ -205,15 +197,8 @@ function serve(config: webpack.Configuration, args: any): Promise { return Promise.resolve() .then(() => { - if (args.watch === 'memory' && args.mode === 'dev') { - return memoryWatch(config, args, app); - } - if (args.watch) { - if (args.watch === 'memory') { - console.warn('Memory watch requires `--mode=dev`. Using file watch instead...'); - } - return fileWatch(config, args); + return fileWatch(config, args, app); } return build(config, args); @@ -266,7 +251,7 @@ const command: Command = { }); options('watch', { - describe: 'watch for file changes: "memory" (dev mode only) or "file" (all modes; default)', + describe: 'watch for file changes', alias: 'w' }); @@ -339,9 +324,6 @@ const command: Command = { } if (args.watch) { - if (args.watch === 'memory') { - console.warn('Memory watch requires the dev server. Using file watch instead...'); - } return fileWatch(config, args); } diff --git a/tests/unit/main.ts b/tests/unit/main.ts index eb43e282..83bf0178 100644 --- a/tests/unit/main.ts +++ b/tests/unit/main.ts @@ -266,15 +266,6 @@ describe('command', () => { assert.isTrue(mockLogger.calledWith('stats', 'dist config', 'watching...')); }); }); - - it('warns when attempting memory watch without the dev server', () => { - const main = mockModule.getModuleUnderTest().default; - return main.run(getMockConfiguration(), { watch: 'memory' }).then(() => { - assert.isTrue( - consoleWarnStub.calledWith('Memory watch requires the dev server. Using file watch instead...') - ); - }); - }); }); describe('serve option', () => { @@ -466,35 +457,17 @@ describe('command', () => { }); }); - it('limits --watch=memory to --mode=dev', () => { + it('registers middleware', () => { const main = mockModule.getModuleUnderTest().default; - return main.run(getMockConfiguration(), { serve: false, watch: 'memory' }).then(() => { - assert.isTrue( - consoleWarnStub.calledWith('Memory watch requires the dev server. Using file watch instead...') - ); - }); - }); - - it('registers middleware with --watch=memory', () => { - const main = mockModule.getModuleUnderTest().default; - const webpackMiddleware = mockModule.getMock('webpack-dev-middleware').ctor; const hotMiddleware = mockModule.getMock('webpack-hot-middleware').ctor; return main .run(getMockConfiguration(), { mode: 'dev', serve: true, - watch: 'memory' + watch: true }) .then(() => { - assert.strictEqual(useStub.callCount, 2); - assert.isTrue( - webpackMiddleware.calledWith(compiler, { - logLevel: 'silent', - noInfo: true, - publicPath: '/', - watchOptions - }) - ); + assert.strictEqual(useStub.callCount, 4); assert.isTrue( hotMiddleware.calledWith(compiler, { heartbeat: 10000 @@ -503,47 +476,19 @@ describe('command', () => { }); }); - it('enables hot module replacement with --watch=memory', () => { + it('enables hot module replacement watch', () => { const main = mockModule.getModuleUnderTest().default; return main .run(getMockConfiguration(), { mode: 'dev', serve: true, - watch: 'memory' + watch: true }) .then(() => { assert.lengthOf(plugins, 2); assert.isTrue(webpack.HotModuleReplacementPlugin.calledWithNew()); assert.isTrue(webpack.NoEmitOnErrorsPlugin.calledWithNew()); - assert.sameMembers(entry.main, [ - 'eventsource-polyfill', - 'webpack-hot-middleware/client?timeout=20000&reload=true' - ]); - }); - }); - - it('provides custom logging with --watch=memory', () => { - const main = mockModule.getModuleUnderTest().default; - - doneHookStub.callsFake((name: string, callback: Function) => { - callback(stats); - }); - - return main - .run(getMockConfiguration(), { - mode: 'dev', - port: 3000, - serve: true, - watch: 'memory' - }) - .then(() => { - assert.isTrue( - mockLogger.calledWith( - 'stats', - { entry, output, plugins, watchOptions }, - 'Listening on port 3000...' - ) - ); + assert.sameMembers(entry.main, ['eventsource-polyfill']); }); }); @@ -580,20 +525,6 @@ describe('command', () => { }); }); - it('does not serve compressed files with memory watch', () => { - const expressStaticGzip = mockModule.getMock('express-static-gzip').ctor; - const main = mockModule.getModuleUnderTest().default; - const rc = { - mode: 'dist', - compression: ['gzip'], - serve: true, - watch: 'memory' - }; - return main.run(getMockConfiguration(), rc).then(() => { - assert.isFalse(expressStaticGzip.called); - }); - }); - it('favors brotli over gzip', () => { const expressStaticGzip = mockModule.getMock('express-static-gzip').ctor; const main = mockModule.getModuleUnderTest().default;