Skip to content

Commit c6d2c00

Browse files
authored
BREAKING CHANGES: create static option and remove replaced options (#2670)
1 parent eb35371 commit c6d2c00

37 files changed

+1670
-805
lines changed

bin/cli-flags.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ module.exports = {
2020
defaultValue: true,
2121
describe: 'Enables/Disables live reloading on changing files',
2222
},
23-
{
24-
name: 'serveIndex',
25-
type: Boolean,
26-
describe: 'Enables/Disables serveIndex middleware',
27-
defaultValue: true,
28-
},
2923
{
3024
name: 'profile',
3125
type: Boolean,
@@ -85,16 +79,11 @@ module.exports = {
8579
describe: 'HTTP/2, must be used with HTTPS',
8680
},
8781
{
88-
name: 'content-base',
82+
name: 'static',
8983
type: String,
90-
describe: 'A directory or URL to serve HTML content from.',
91-
group: RESPONSE_GROUP,
92-
},
93-
{
94-
name: 'watch-content-base',
95-
type: Boolean,
96-
describe: 'Enable live-reloading of the content-base.',
84+
describe: 'A directory to serve static content from.',
9785
group: RESPONSE_GROUP,
86+
multiple: true,
9887
},
9988
{
10089
name: 'history-api-fallback',

bin/options.js

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ const options = {
1717
describe: 'Enables/Disables live reloading on changing files',
1818
default: true,
1919
},
20-
serveIndex: {
21-
type: 'boolean',
22-
describe: 'Enables/Disables serveIndex middleware',
23-
default: true,
24-
},
2520
profile: {
2621
type: 'boolean',
2722
describe: 'Print compilation profile data for progress steps',
@@ -75,14 +70,9 @@ const options = {
7570
group: SSL_GROUP,
7671
describe: 'HTTP/2, must be used with HTTPS',
7772
},
78-
'content-base': {
73+
static: {
7974
type: 'string',
80-
describe: 'A directory or URL to serve HTML content from.',
81-
group: RESPONSE_GROUP,
82-
},
83-
'watch-content-base': {
84-
type: 'boolean',
85-
describe: 'Enable live-reloading of the content-base.',
75+
describe: 'A directory to serve static content from.',
8676
group: RESPONSE_GROUP,
8777
},
8878
'history-api-fallback': {

lib/Server.js

Lines changed: 47 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const webpackDevMiddleware = require('webpack-dev-middleware');
1818
const getFilenameFromUrl = require('webpack-dev-middleware/dist/utils/getFilenameFromUrl')
1919
.default;
2020
const validateOptions = require('schema-utils');
21-
const isAbsoluteUrl = require('is-absolute-url');
2221
const normalizeOptions = require('./utils/normalizeOptions');
2322
const updateCompiler = require('./utils/updateCompiler');
2423
const getCertificate = require('./utils/getCertificate');
@@ -304,112 +303,43 @@ class Server {
304303
}
305304

306305
setupStaticFeature() {
307-
const contentBase = this.options.contentBase;
308-
const contentBasePublicPath = this.options.contentBasePublicPath;
309-
310-
if (Array.isArray(contentBase)) {
311-
contentBase.forEach((item, index) => {
312-
let publicPath = contentBasePublicPath;
313-
314-
if (
315-
Array.isArray(contentBasePublicPath) &&
316-
contentBasePublicPath[index]
317-
) {
318-
publicPath = contentBasePublicPath[index] || contentBasePublicPath[0];
319-
}
320-
321-
this.app.use(publicPath, express.static(item));
322-
});
323-
} else if (isAbsoluteUrl(String(contentBase))) {
324-
this.logger.warn(
325-
'Using a URL as contentBase is deprecated and will be removed in the next major version. Please use the proxy option instead.'
326-
);
327-
328-
this.logger.warn(
329-
'proxy: {\n\t"*": "<your current contentBase configuration>"\n}'
330-
);
331-
332-
// Redirect every request to contentBase
333-
this.app.get('*', (req, res) => {
334-
res.writeHead(302, {
335-
Location: contentBase + req.path + (req._parsedUrl.search || ''),
336-
});
337-
338-
res.end();
339-
});
340-
} else if (typeof contentBase === 'number') {
341-
this.logger.warn(
342-
'Using a number as contentBase is deprecated and will be removed in the next major version. Please use the proxy option instead.'
343-
);
344-
345-
this.logger.warn(
346-
'proxy: {\n\t"*": "//localhost:<your current contentBase configuration>"\n}'
347-
);
348-
349-
// Redirect every request to the port contentBase
350-
this.app.get('*', (req, res) => {
351-
res.writeHead(302, {
352-
Location: `//localhost:${contentBase}${req.path}${
353-
req._parsedUrl.search || ''
354-
}`,
355-
});
356-
357-
res.end();
306+
this.options.static.forEach((staticOption) => {
307+
staticOption.publicPath.forEach((publicPath) => {
308+
this.app.use(
309+
publicPath,
310+
express.static(staticOption.directory, staticOption.staticOptions)
311+
);
358312
});
359-
} else {
360-
// route content request
361-
this.app.use(
362-
contentBasePublicPath,
363-
express.static(contentBase, this.options.staticOptions)
364-
);
365-
}
313+
});
366314
}
367315

368-
setupServeIndexFeature() {
369-
const contentBase = this.options.contentBase;
370-
const contentBasePublicPath = this.options.contentBasePublicPath;
371-
372-
if (Array.isArray(contentBase)) {
373-
contentBase.forEach((item) => {
374-
this.app.use(contentBasePublicPath, (req, res, next) => {
375-
// serve-index doesn't fallthrough non-get/head request to next middleware
376-
if (req.method !== 'GET' && req.method !== 'HEAD') {
377-
return next();
378-
}
316+
setupStaticServeIndexFeature() {
317+
this.options.static.forEach((staticOption) => {
318+
staticOption.publicPath.forEach((publicPath) => {
319+
if (staticOption.serveIndex) {
320+
this.app.use(publicPath, (req, res, next) => {
321+
// serve-index doesn't fallthrough non-get/head request to next middleware
322+
if (req.method !== 'GET' && req.method !== 'HEAD') {
323+
return next();
324+
}
379325

380-
serveIndex(item, { icons: true })(req, res, next);
381-
});
382-
});
383-
} else if (
384-
typeof contentBase !== 'number' &&
385-
!isAbsoluteUrl(String(contentBase))
386-
) {
387-
this.app.use(contentBasePublicPath, (req, res, next) => {
388-
// serve-index doesn't fallthrough non-get/head request to next middleware
389-
if (req.method !== 'GET' && req.method !== 'HEAD') {
390-
return next();
326+
serveIndex(staticOption.directory, staticOption.serveIndex)(
327+
req,
328+
res,
329+
next
330+
);
331+
});
391332
}
392-
393-
serveIndex(contentBase, { icons: true })(req, res, next);
394333
});
395-
}
334+
});
396335
}
397336

398-
setupWatchStaticFeature() {
399-
const contentBase = this.options.contentBase;
400-
401-
if (isAbsoluteUrl(String(contentBase)) || typeof contentBase === 'number') {
402-
throw new Error('Watching remote files is not supported.');
403-
} else if (Array.isArray(contentBase)) {
404-
contentBase.forEach((item) => {
405-
if (isAbsoluteUrl(String(item)) || typeof item === 'number') {
406-
throw new Error('Watching remote files is not supported.');
407-
}
408-
this._watch(item);
409-
});
410-
} else {
411-
this._watch(contentBase);
412-
}
337+
setupStaticWatchFeature() {
338+
this.options.static.forEach((staticOption) => {
339+
if (staticOption.watch) {
340+
this.watchFiles(staticOption.directory, staticOption.watch);
341+
}
342+
});
413343
}
414344

415345
setupOnBeforeSetupMiddlewareFeature() {
@@ -449,17 +379,14 @@ class Server {
449379
this.setupHistoryApiFallbackFeature();
450380
}
451381
},
452-
// Todo rename to `static` in future major release
453-
contentBaseFiles: () => {
382+
static: () => {
454383
this.setupStaticFeature();
455384
},
456-
// Todo rename to `serveIndex` in future major release
457-
contentBaseIndex: () => {
458-
this.setupServeIndexFeature();
385+
staticServeIndex: () => {
386+
this.setupStaticServeIndexFeature();
459387
},
460-
// Todo rename to `watchStatic` in future major release
461-
watchContentBase: () => {
462-
this.setupWatchStaticFeature();
388+
staticWatch: () => {
389+
this.setupStaticWatchFeature();
463390
},
464391
onBeforeSetupMiddleware: () => {
465392
if (typeof this.options.onBeforeSetupMiddleware === 'function') {
@@ -501,24 +428,20 @@ class Server {
501428
runnableFeatures.push('proxy', 'middleware');
502429
}
503430

504-
if (this.options.contentBase !== false) {
505-
runnableFeatures.push('contentBaseFiles');
431+
if (this.options.static) {
432+
runnableFeatures.push('static');
506433
}
507434

508435
if (this.options.historyApiFallback) {
509436
runnableFeatures.push('historyApiFallback', 'middleware');
510437

511-
if (this.options.contentBase !== false) {
512-
runnableFeatures.push('contentBaseFiles');
438+
if (this.options.static) {
439+
runnableFeatures.push('static');
513440
}
514441
}
515442

516-
if (this.options.contentBase && this.options.serveIndex) {
517-
runnableFeatures.push('contentBaseIndex');
518-
}
519-
520-
if (this.options.watchContentBase) {
521-
runnableFeatures.push('watchContentBase');
443+
if (this.options.static) {
444+
runnableFeatures.push('staticServeIndex', 'staticWatch');
522445
}
523446

524447
runnableFeatures.push('magicHtml');
@@ -903,31 +826,31 @@ class Server {
903826
}
904827
}
905828

906-
_watch(watchPath) {
829+
watchFiles(watchPath, watchOptions) {
907830
// duplicate the same massaging of options that watchpack performs
908831
// https://github.com/webpack/watchpack/blob/master/lib/DirectoryWatcher.js#L49
909832
// this isn't an elegant solution, but we'll improve it in the future
910833
// eslint-disable-next-line no-undefined
911-
const usePolling = this.options.watchOptions.poll ? true : undefined;
834+
const usePolling = watchOptions.poll ? true : undefined;
912835
const interval =
913-
typeof this.options.watchOptions.poll === 'number'
914-
? this.options.watchOptions.poll
836+
typeof watchOptions.poll === 'number'
837+
? watchOptions.poll
915838
: // eslint-disable-next-line no-undefined
916839
undefined;
917840

918-
const watchOptions = {
841+
const finalWatchOptions = {
919842
ignoreInitial: true,
920843
persistent: true,
921844
followSymlinks: false,
922845
atomic: false,
923846
alwaysStat: true,
924847
ignorePermissionErrors: true,
925-
ignored: this.options.watchOptions.ignored,
848+
ignored: watchOptions.ignored,
926849
usePolling,
927850
interval,
928851
};
929852

930-
const watcher = chokidar.watch(watchPath, watchOptions);
853+
const watcher = chokidar.watch(watchPath, finalWatchOptions);
931854
// disabling refreshing on changing the content
932855
if (this.options.liveReload) {
933856
watcher.on('change', () => {

0 commit comments

Comments
 (0)