@salesforce/pwa-kit-dev 3.0.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +14 -0
- package/README.md +35 -0
- package/bin/pwa-kit-dev.js +461 -0
- package/configs/babel/babel-config.js +34 -0
- package/configs/eslint/README.md +21 -0
- package/configs/eslint/eslint-config.js +11 -0
- package/configs/eslint/index.js +11 -0
- package/configs/eslint/no-react.js +18 -0
- package/configs/eslint/partials/base.js +38 -0
- package/configs/eslint/partials/jest.js +24 -0
- package/configs/eslint/partials/react.js +29 -0
- package/configs/eslint/partials/typescript-permit-any.js +31 -0
- package/configs/eslint/partials/typescript.js +17 -0
- package/configs/eslint/recommended.js +20 -0
- package/configs/eslint/safe-types.js +20 -0
- package/configs/jest/jest-babel-transform.js +19 -0
- package/configs/jest/jest.config.js +33 -0
- package/configs/jest/mocks/fileMock.js +9 -0
- package/configs/jest/mocks/styleMock.js +9 -0
- package/configs/jest/mocks/svgMock.js +11 -0
- package/configs/webpack/config-names.js +24 -0
- package/configs/webpack/config.js +425 -0
- package/configs/webpack/overrides-plugin.js +120 -0
- package/configs/webpack/plugins.js +92 -0
- package/package.json +150 -0
- package/scripts/version.js +22 -0
- package/ssr/server/build-dev-server.js +443 -0
- package/ssr/server/build-dev-server.test.js +635 -0
- package/ssr/server/loading-screen/css/main.css +272 -0
- package/ssr/server/loading-screen/css/normalize.css +349 -0
- package/ssr/server/loading-screen/img/cloud-1.svg +1 -0
- package/ssr/server/loading-screen/img/cloud-2.svg +1 -0
- package/ssr/server/loading-screen/img/cloud-3.svg +1 -0
- package/ssr/server/loading-screen/img/cloud.svg +1 -0
- package/ssr/server/loading-screen/img/codey-arm.svg +1 -0
- package/ssr/server/loading-screen/img/codey-bear.svg +1 -0
- package/ssr/server/loading-screen/img/codey-bg.svg +1 -0
- package/ssr/server/loading-screen/img/codey-cloud.svg +1 -0
- package/ssr/server/loading-screen/img/codey-search.svg +1 -0
- package/ssr/server/loading-screen/img/codey.svg +1 -0
- package/ssr/server/loading-screen/img/codeyCarry.svg +1 -0
- package/ssr/server/loading-screen/img/devDocumentation.svg +1 -0
- package/ssr/server/loading-screen/img/devGithub.svg +1 -0
- package/ssr/server/loading-screen/img/devTrailhead.svg +1 -0
- package/ssr/server/loading-screen/img/logo.svg +1 -0
- package/ssr/server/loading-screen/img/slds_spinner_brand_9EA9F1.gif +0 -0
- package/ssr/server/loading-screen/index.html +130 -0
- package/ssr/server/test_fixtures/app/main.js +6 -0
- package/ssr/server/test_fixtures/app/static/favicon.ico +0 -0
- package/ssr/server/test_fixtures/localhost.pem +45 -0
- package/utils/script-utils.js +312 -0
- package/utils/script-utils.test.js +282 -0
- package/utils/test-fixtures/minimal-built-app/ssr.js +9 -0
- package/utils/test-fixtures/minimal-built-app/static/favicon.ico +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.shouldCompress = exports.setLocalAssetHeaders = exports.makeErrorHandler = exports.DevServerMixin = exports.DevServerFactory = void 0;
|
|
7
|
+
var _compression = _interopRequireDefault(require("compression"));
|
|
8
|
+
var _express = _interopRequireDefault(require("express"));
|
|
9
|
+
var _path = _interopRequireDefault(require("path"));
|
|
10
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
11
|
+
var _https = _interopRequireDefault(require("https"));
|
|
12
|
+
var _http = _interopRequireDefault(require("http"));
|
|
13
|
+
var _mimeTypes = _interopRequireDefault(require("mime-types"));
|
|
14
|
+
var _webpack = _interopRequireDefault(require("webpack"));
|
|
15
|
+
var _webpackDevMiddleware = _interopRequireDefault(require("webpack-dev-middleware"));
|
|
16
|
+
var _webpackHotServerMiddleware = _interopRequireDefault(require("webpack-hot-server-middleware"));
|
|
17
|
+
var _webpackHotMiddleware = _interopRequireDefault(require("webpack-hot-middleware"));
|
|
18
|
+
var _open = _interopRequireDefault(require("open"));
|
|
19
|
+
var _requireFromString = _interopRequireDefault(require("require-from-string"));
|
|
20
|
+
var _buildRemoteServer = require("@salesforce/pwa-kit-runtime/ssr/server/build-remote-server");
|
|
21
|
+
var _ssrShared = require("@salesforce/pwa-kit-runtime/utils/ssr-shared");
|
|
22
|
+
var _configNames = require("../../configs/webpack/config-names");
|
|
23
|
+
var _crypto = require("crypto");
|
|
24
|
+
var _chalk = _interopRequireDefault(require("chalk"));
|
|
25
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
26
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /*
|
|
27
|
+
* Copyright (c) 2022, Salesforce, Inc.
|
|
28
|
+
* All rights reserved.
|
|
29
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
30
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
31
|
+
*/
|
|
32
|
+
const CONTENT_TYPE = 'content-type';
|
|
33
|
+
const CONTENT_ENCODING = 'content-encoding';
|
|
34
|
+
const NO_CACHE = 'max-age=0, nocache, nostore, must-revalidate';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
const DevServerMixin = {
|
|
40
|
+
/**
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
_logStartupMessage(options) {
|
|
44
|
+
console.log(`Starting the DevServer on ${_chalk.default.cyan(this._getDevServerURL(options))}`);
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
_getProtocol(options) {
|
|
50
|
+
return process.env.DEV_SERVER_PROTOCOL || options.protocol;
|
|
51
|
+
},
|
|
52
|
+
/**
|
|
53
|
+
* @private
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
57
|
+
_getDefaultCacheControl(options) {
|
|
58
|
+
return NO_CACHE;
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
_strictSSL(options) {
|
|
64
|
+
return options.strictSSL;
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Since dev server does not have access to apiGateway event object,
|
|
68
|
+
* here we generate an uuid and assign it under locals
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
_setRequestId(app) {
|
|
72
|
+
app.use((req, res, next) => {
|
|
73
|
+
res.locals.requestId = (0, _crypto.randomUUID)();
|
|
74
|
+
next();
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
/**
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
_setCompression(app) {
|
|
81
|
+
app.use((0, _compression.default)({
|
|
82
|
+
level: 9,
|
|
83
|
+
filter: shouldCompress
|
|
84
|
+
}));
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* @private
|
|
88
|
+
*/
|
|
89
|
+
_setupMetricsFlushing(app) {
|
|
90
|
+
// Flush metrics at the end of sending. We do this here to
|
|
91
|
+
// keep the code paths consistent between local and remote
|
|
92
|
+
// servers. For the remote server, the flushing is done
|
|
93
|
+
// by the Lambda integration.
|
|
94
|
+
app.use((req, res, next) => {
|
|
95
|
+
res.on('finish', () => app.metrics.flush());
|
|
96
|
+
next();
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
104
|
+
_setupProxying(app, options) {
|
|
105
|
+
_ssrShared.proxyConfigs.forEach(config => {
|
|
106
|
+
app.use(config.proxyPath, config.proxy);
|
|
107
|
+
app.use(config.cachingPath, config.cachingProxy);
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
_addSDKInternalHandlers(app) {
|
|
114
|
+
// This is separated out because these routes must not have our SSR middleware applied to them.
|
|
115
|
+
// But the SSR render function must!
|
|
116
|
+
|
|
117
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
118
|
+
let config = require('../../configs/webpack/config');
|
|
119
|
+
const projectWebpackPath = _path.default.resolve(app.options.projectDir, 'webpack.config.js');
|
|
120
|
+
if (_fs.default.existsSync(projectWebpackPath)) {
|
|
121
|
+
config = require(projectWebpackPath);
|
|
122
|
+
}
|
|
123
|
+
app.__compiler = (0, _webpack.default)(config);
|
|
124
|
+
app.__devMiddleware = (0, _webpackDevMiddleware.default)(app.__compiler, {
|
|
125
|
+
serverSideRender: true
|
|
126
|
+
});
|
|
127
|
+
app.__webpackReady = () => Boolean(app.__devMiddleware.context.state);
|
|
128
|
+
app.__devMiddleware.waitUntilValid(() => {
|
|
129
|
+
// Be just a little more generous before letting eg. Lighthouse hit it!
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
console.log(_chalk.default.cyan('First build complete'));
|
|
132
|
+
}, 75);
|
|
133
|
+
});
|
|
134
|
+
if (config.some(cnf => cnf.name === _configNames.SERVER)) {
|
|
135
|
+
app.__hotServerMiddleware = (0, _webpackHotServerMiddleware.default)(app.__compiler);
|
|
136
|
+
}
|
|
137
|
+
app.use('/mobify/bundle/development', app.__devMiddleware);
|
|
138
|
+
app.__hmrMiddleware = (_, res) => res.status(501).send('Hot Module Reloading is disabled.');
|
|
139
|
+
const clientCompiler = app.__compiler.compilers.find(compiler => compiler.name === _configNames.CLIENT);
|
|
140
|
+
if (clientCompiler && process.env.HMR !== 'false') {
|
|
141
|
+
app.__hmrMiddleware = (0, _webpackHotMiddleware.default)(clientCompiler, {
|
|
142
|
+
path: '/'
|
|
143
|
+
}); // path is relative to the endpoint the middleware is attached to
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
app.use('/__mrt/hmr', app.__hmrMiddleware);
|
|
147
|
+
app.use('/__mrt/status', (req, res) => {
|
|
148
|
+
return res.json({
|
|
149
|
+
ready: app.__webpackReady()
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
app.use('/__mrt/loading-screen/', _express.default.static(_path.default.resolve(__dirname, 'loading-screen'), {
|
|
153
|
+
dotFiles: 'deny'
|
|
154
|
+
}));
|
|
155
|
+
app.get('/__mrt/clear-browser-data', (_, res) => {
|
|
156
|
+
console.log(_chalk.default.cyan('Clearing browser data'), '(cache, service worker, web storage for browsers supporting Clear-Site-Data header)');
|
|
157
|
+
console.log('For more info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data#browser_compatibility');
|
|
158
|
+
console.log('');
|
|
159
|
+
|
|
160
|
+
// Note: this header value needs the double quotes.
|
|
161
|
+
res.set('Clear-Site-Data', '"cache", "storage"');
|
|
162
|
+
res.send();
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
/**
|
|
166
|
+
* @private
|
|
167
|
+
*/
|
|
168
|
+
_addStaticAssetServing(app) {
|
|
169
|
+
// Proxy bundle asset requests to the local
|
|
170
|
+
// build directory.
|
|
171
|
+
app.use('/mobify/bundle/development', _express.default.static(_path.default.resolve(process.cwd(), 'src'), {
|
|
172
|
+
dotFiles: 'deny',
|
|
173
|
+
setHeaders: setLocalAssetHeaders,
|
|
174
|
+
fallthrough: true
|
|
175
|
+
}));
|
|
176
|
+
},
|
|
177
|
+
/**
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
_addDevServerGarbageCollection(app) {
|
|
181
|
+
app.use((req, res, next) => {
|
|
182
|
+
const done = () => {
|
|
183
|
+
// We collect garbage because when a Lambda environment is
|
|
184
|
+
// re-used, we want to start with minimal memory usage. This
|
|
185
|
+
// call typically takes less than 100mS, and can dramatically
|
|
186
|
+
// reduce memory usage, so we accept the runtime cost.
|
|
187
|
+
// For the local dev server, we do this now. For a remote
|
|
188
|
+
// server, we use a different strategy (see createLambdaHandler).
|
|
189
|
+
req.app._collectGarbage();
|
|
190
|
+
};
|
|
191
|
+
res.on('finish', done);
|
|
192
|
+
res.on('close', done);
|
|
193
|
+
next();
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
serveStaticFile(filePath, opts = {}) {
|
|
197
|
+
// Warning: Ugly part of the Bundle spec that we need to maintain.
|
|
198
|
+
//
|
|
199
|
+
// This function assumes that an SDK build step will copy all
|
|
200
|
+
// non-webpacked assets from the 'app' dir to the 'build' dir.
|
|
201
|
+
//
|
|
202
|
+
// If you look carefully through the history, this has never
|
|
203
|
+
// been true though – assets get copied from app/static to
|
|
204
|
+
// build/static but this isn't really clear from the API.
|
|
205
|
+
//
|
|
206
|
+
// To see where those assets get copied, see here:
|
|
207
|
+
//
|
|
208
|
+
// packages/pwa-kit-dev/src/configs/webpack/config.js
|
|
209
|
+
//
|
|
210
|
+
// We have plans to make a robust Bundle spec in 246!
|
|
211
|
+
//
|
|
212
|
+
// Discussion here:
|
|
213
|
+
//
|
|
214
|
+
// https://salesforce-internal.slack.com/archives/C8YDDMKFZ/p1677793769255659?thread_ts=1677791840.174309&cid=C8YDDMKFZ
|
|
215
|
+
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
217
|
+
const pkg = require(_path.default.resolve(process.cwd(), 'package.json'));
|
|
218
|
+
return (req, res) => {
|
|
219
|
+
var _pkg$ccExtensibility, _pkg$ccExtensibility$;
|
|
220
|
+
const baseDir = _path.default.resolve(req.app.options.projectDir, (pkg === null || pkg === void 0 ? void 0 : (_pkg$ccExtensibility = pkg.ccExtensibility) === null || _pkg$ccExtensibility === void 0 ? void 0 : (_pkg$ccExtensibility$ = _pkg$ccExtensibility.overridesDir) === null || _pkg$ccExtensibility$ === void 0 ? void 0 : _pkg$ccExtensibility$.replace(/^\//, '')) ?? '', 'app');
|
|
221
|
+
return this._serveStaticFile(req, res, baseDir, filePath, opts);
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
serveServiceWorker(req, res) {
|
|
225
|
+
req.app.__devMiddleware.waitUntilValid(() => {
|
|
226
|
+
const sourceMap = req.path.endsWith('.map');
|
|
227
|
+
const file = sourceMap ? 'worker.js.map' : 'worker.js';
|
|
228
|
+
const type = sourceMap ? '.js.map' : '.js';
|
|
229
|
+
const content = DevServerFactory._getWebpackAsset(req, _configNames.CLIENT_OPTIONAL, file);
|
|
230
|
+
if (content === null) {
|
|
231
|
+
// Service worker does not exist. Reminder that SW is optional for MRT apps.
|
|
232
|
+
res.sendStatus(404);
|
|
233
|
+
} else {
|
|
234
|
+
res.type(type);
|
|
235
|
+
res.send(content);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
render(req, res, next) {
|
|
240
|
+
const app = req.app;
|
|
241
|
+
if (app.__webpackReady()) {
|
|
242
|
+
app.__hotServerMiddleware(req, res, next);
|
|
243
|
+
} else {
|
|
244
|
+
this._redirectToLoadingScreen(req, res, next);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
/**
|
|
248
|
+
* @private
|
|
249
|
+
*/
|
|
250
|
+
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
252
|
+
_redirectToLoadingScreen(req, res, next) {
|
|
253
|
+
res.redirect('/__mrt/loading-screen/index.html?loading=1');
|
|
254
|
+
},
|
|
255
|
+
/**
|
|
256
|
+
* @private
|
|
257
|
+
*/
|
|
258
|
+
_getDevServerHostAndPort(options) {
|
|
259
|
+
const split = options.devServerHostName.split(':');
|
|
260
|
+
const hostname = split.length === 2 ? split[0] : options.devServerHostName;
|
|
261
|
+
const port = split.length === 2 ? split[1] : options.port;
|
|
262
|
+
return {
|
|
263
|
+
hostname,
|
|
264
|
+
port
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
/**
|
|
268
|
+
* @private
|
|
269
|
+
*/
|
|
270
|
+
_getDevServerURL(options) {
|
|
271
|
+
const {
|
|
272
|
+
protocol
|
|
273
|
+
} = options;
|
|
274
|
+
const {
|
|
275
|
+
hostname,
|
|
276
|
+
port
|
|
277
|
+
} = this._getDevServerHostAndPort(options);
|
|
278
|
+
return `${protocol}://${hostname}:${port}`;
|
|
279
|
+
},
|
|
280
|
+
/**
|
|
281
|
+
* @private
|
|
282
|
+
*/
|
|
283
|
+
_createHandler(app) {
|
|
284
|
+
const {
|
|
285
|
+
protocol,
|
|
286
|
+
sslFilePath
|
|
287
|
+
} = app.options;
|
|
288
|
+
const {
|
|
289
|
+
hostname,
|
|
290
|
+
port
|
|
291
|
+
} = this._getDevServerHostAndPort(app.options);
|
|
292
|
+
let server;
|
|
293
|
+
if (protocol === 'https') {
|
|
294
|
+
const sslFile = _fs.default.readFileSync(sslFilePath);
|
|
295
|
+
server = _https.default.createServer({
|
|
296
|
+
key: sslFile,
|
|
297
|
+
cert: sslFile
|
|
298
|
+
}, app);
|
|
299
|
+
} else {
|
|
300
|
+
server = _http.default.createServer(app);
|
|
301
|
+
}
|
|
302
|
+
server.on('error', makeErrorHandler(process, server, console.log));
|
|
303
|
+
server.on('close', () => app.applicationCache.close());
|
|
304
|
+
server.listen({
|
|
305
|
+
hostname,
|
|
306
|
+
port
|
|
307
|
+
}, () => {
|
|
308
|
+
/* istanbul ignore next */
|
|
309
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
310
|
+
(0, _open.default)(`${this._getDevServerURL(app.options)}/__mrt/loading-screen/index.html?loading=1`);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
return {
|
|
314
|
+
handler: undefined,
|
|
315
|
+
server,
|
|
316
|
+
app
|
|
317
|
+
};
|
|
318
|
+
},
|
|
319
|
+
/**
|
|
320
|
+
* Load any request processor code to emulate in the dev server the code
|
|
321
|
+
* that would run on a Lambda Edge function.
|
|
322
|
+
*
|
|
323
|
+
* @private
|
|
324
|
+
*/
|
|
325
|
+
_getRequestProcessor(req) {
|
|
326
|
+
const compiled = this._getWebpackAsset(req, _configNames.REQUEST_PROCESSOR, 'request-processor.js');
|
|
327
|
+
if (compiled) {
|
|
328
|
+
const module = (0, _requireFromString.default)(compiled);
|
|
329
|
+
if (!module.processRequest) {
|
|
330
|
+
throw new Error(`Request processor module "request-processor.js" does not export processRequest`);
|
|
331
|
+
}
|
|
332
|
+
return module;
|
|
333
|
+
} else {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
/**
|
|
338
|
+
* Return the compiled source for a webpack asset as a string.
|
|
339
|
+
*
|
|
340
|
+
* @param req
|
|
341
|
+
* @param compilerName
|
|
342
|
+
* @param fileName
|
|
343
|
+
* @returns {null|String}
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
_getWebpackAsset(req, compilerName, fileName) {
|
|
347
|
+
if (req.app.__webpackReady()) {
|
|
348
|
+
const outputFileSystem = req.app.__devMiddleware.context.outputFileSystem;
|
|
349
|
+
const jsonWebpackStats = req.app.__devMiddleware.context.stats.toJson();
|
|
350
|
+
try {
|
|
351
|
+
const rp = jsonWebpackStats.children.find(child => child.name === compilerName);
|
|
352
|
+
const assetPath = _path.default.join(rp.outputPath, fileName);
|
|
353
|
+
return outputFileSystem.readFileSync(assetPath, 'utf-8');
|
|
354
|
+
} catch (e) {
|
|
355
|
+
// The file doesn't exist – this is fine, many are optional
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
// The file isn't compiled yet
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Set the headers for a bundle asset. This is used only in local
|
|
367
|
+
* dev server mode.
|
|
368
|
+
*
|
|
369
|
+
* @private
|
|
370
|
+
* @param res - the response object
|
|
371
|
+
* @param assetPath - the path to the asset file (with no query string
|
|
372
|
+
* or other URL elements)
|
|
373
|
+
*/
|
|
374
|
+
exports.DevServerMixin = DevServerMixin;
|
|
375
|
+
const setLocalAssetHeaders = (res, assetPath) => {
|
|
376
|
+
const base = _path.default.basename(assetPath);
|
|
377
|
+
const contentType = _mimeTypes.default.lookup(base);
|
|
378
|
+
res.set(CONTENT_TYPE, contentType); // || 'application/octet-stream'
|
|
379
|
+
|
|
380
|
+
// Stat the file and return the last-modified Date
|
|
381
|
+
// in RFC1123 format. Also use that value as the ETag
|
|
382
|
+
// and Last-Modified
|
|
383
|
+
const mtime = _fs.default.statSync(assetPath).mtime;
|
|
384
|
+
const mtimeRFC1123 = mtime.toUTCString();
|
|
385
|
+
res.set('date', mtimeRFC1123);
|
|
386
|
+
res.set('last-modified', mtimeRFC1123);
|
|
387
|
+
res.set('etag', mtime.getTime());
|
|
388
|
+
|
|
389
|
+
// We don't cache local bundle assets
|
|
390
|
+
res.set('cache-control', NO_CACHE);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Crash the app with a user-friendly message when the port is already in use.
|
|
395
|
+
*
|
|
396
|
+
* @private
|
|
397
|
+
* @param {*} proc - Node's process module
|
|
398
|
+
* @param {*} server - the server to attach the listener to
|
|
399
|
+
* @param {*} log - logging function
|
|
400
|
+
*/
|
|
401
|
+
exports.setLocalAssetHeaders = setLocalAssetHeaders;
|
|
402
|
+
const makeErrorHandler = (proc, server, log) => {
|
|
403
|
+
return e => {
|
|
404
|
+
if (e.code === 'EADDRINUSE') {
|
|
405
|
+
log(`This port is already being used by another process.`);
|
|
406
|
+
server.close();
|
|
407
|
+
proc.exit(2);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Filter function for compression module.
|
|
414
|
+
*
|
|
415
|
+
* @private
|
|
416
|
+
* @param req {IncomingMessage} ExpressJS Request
|
|
417
|
+
* @param res {ServerResponse} ExpressJS Response
|
|
418
|
+
* @returns {Boolean}
|
|
419
|
+
*/
|
|
420
|
+
exports.makeErrorHandler = makeErrorHandler;
|
|
421
|
+
const shouldCompress = (req, res) => {
|
|
422
|
+
// If there is already a CONTENT_ENCODING header, then we
|
|
423
|
+
// do not apply any compression. This allows project code
|
|
424
|
+
// to handle encoding, if required.
|
|
425
|
+
if (res.getHeader(CONTENT_ENCODING)) {
|
|
426
|
+
// Set a flag on the response so that the persistent cache logic
|
|
427
|
+
// can tell there was already a content-encoding header.
|
|
428
|
+
res.locals.contentEncodingSet = true;
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Let the compression module make the decision about compressing.
|
|
433
|
+
// Even if we return true here, the module may still choose
|
|
434
|
+
// not to compress the data.
|
|
435
|
+
return _compression.default.filter(req, res);
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* @private
|
|
440
|
+
*/
|
|
441
|
+
exports.shouldCompress = shouldCompress;
|
|
442
|
+
const DevServerFactory = _extends({}, _buildRemoteServer.RemoteServerFactory, DevServerMixin);
|
|
443
|
+
exports.DevServerFactory = DevServerFactory;
|