@modern-js/prod-server 2.9.0 → 2.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @modern-js/prod-server
2
2
 
3
+ ## 2.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d8bbf28: feat: .env file should be load when prod server is started
8
+ feat: 在 server 启动时,.env 文件应该被加载
9
+
10
+ ### Patch Changes
11
+
12
+ - 3e0bd50: feat: when enable bff handle render, support use `useContext` to get framework plugin context in data loader.
13
+ feat: 当开启 BFF 托管渲染时,支持在 data loader 中使用 `useContext` 获取框架插件提供的上下文。
14
+ - 92d247f: fix: support tools.devServer.header include string[] type, remove get & delete & apply api in hook or middleware api
15
+ fix: 支持 tools.devServer.header 包含字符串数组类型,移除 Hook 和 Middleware 中对 响应 Cookie 的获取、删除操作
16
+ - 0da32d0: chore: upgrade jest and puppeteer
17
+ chore: 升级 jest 和 puppeteer 到 latest
18
+ - 0d9962b: fix: add types field in package.json
19
+ fix: 添加 package.json 中的 types 字段
20
+ - Updated dependencies [3e0bd50]
21
+ - Updated dependencies [0da32d0]
22
+ - Updated dependencies [fbefa7e]
23
+ - Updated dependencies [4d54233]
24
+ - Updated dependencies [6db4864]
25
+ - @modern-js/server-core@2.10.0
26
+ - @modern-js/utils@2.10.0
27
+
3
28
  ## 2.9.0
4
29
 
5
30
  ### Patch Changes
@@ -39,13 +39,9 @@ var import_template = require("./template");
39
39
  class Response {
40
40
  constructor(res) {
41
41
  this.res = res;
42
- this._cookie = import_cookie.default.parse(res.getHeader("set-cookie") || "");
43
42
  this.cookies = {
44
- get: this.getCookie.bind(this),
45
43
  set: this.setCookie.bind(this),
46
- delete: this.deleteCookie.bind(this),
47
- clear: this.clearCookie.bind(this),
48
- apply: this.applyCookie.bind(this)
44
+ clear: this.clearCookie.bind(this)
49
45
  };
50
46
  }
51
47
  get(key) {
@@ -57,29 +53,14 @@ class Response {
57
53
  status(code) {
58
54
  this.res.statusCode = code;
59
55
  }
60
- getCookie(key) {
61
- return this._cookie[key];
62
- }
63
- setCookie(key, value) {
64
- this._cookie[key] = value;
65
- }
66
- deleteCookie(key) {
67
- if (this._cookie[key]) {
68
- delete this._cookie[key];
69
- }
56
+ setCookie(key, value, options) {
57
+ const cookieValue = this.res.getHeader("set-cookie");
58
+ const fmt = Array.isArray(cookieValue) ? cookieValue : [cookieValue].filter(Boolean);
59
+ fmt.push(import_cookie.default.serialize(key, value, options));
60
+ this.res.setHeader("set-cookie", fmt.length === 1 ? fmt[0] : fmt);
70
61
  }
71
62
  clearCookie() {
72
- this._cookie = {};
73
- }
74
- applyCookie() {
75
- const str = Object.entries(this._cookie).map(([key, value]) => {
76
- return import_cookie.default.serialize(key, value);
77
- }).join("; ");
78
- if (str) {
79
- this.res.setHeader("set-cookie", str);
80
- } else {
81
- this.res.removeHeader("set-cookie");
82
- }
63
+ this.res.removeHeader("set-cookie");
83
64
  }
84
65
  raw(body, options) {
85
66
  const { status, headers = {} } = options || {};
@@ -36,6 +36,7 @@ var import_constants = require("../../constants");
36
36
  var import_static = require("./static");
37
37
  var import_reader = require("./reader");
38
38
  var ssr = __toESM(require("./ssr"));
39
+ var import_utils2 = require("./utils");
39
40
  const createRenderHandler = ({
40
41
  distDir,
41
42
  staticGenerate,
@@ -87,7 +88,7 @@ const createRenderHandler = ({
87
88
  }
88
89
  }
89
90
  return {
90
- content,
91
+ content: route.entryName ? (0, import_utils2.injectSeverData)(content.toString(), ctx) : content,
91
92
  contentType: import_utils.mime.contentType(import_path.default.extname(templatePath))
92
93
  };
93
94
  };
@@ -34,6 +34,7 @@ var import_path = __toESM(require("path"));
34
34
  var import_utils = require("@modern-js/utils");
35
35
  var import_cache = __toESM(require("./cache"));
36
36
  var import_measure = require("./measure");
37
+ var import_utils2 = require("./utils");
37
38
  const render = async (ctx, renderOptions, runner) => {
38
39
  var _a;
39
40
  const {
@@ -98,13 +99,13 @@ const render = async (ctx, renderOptions, runner) => {
98
99
  }
99
100
  if (typeof content === "string") {
100
101
  return {
101
- content,
102
+ content: (0, import_utils2.injectSeverData)(content, ctx),
102
103
  contentType: import_utils.mime.contentType("html")
103
104
  };
104
105
  } else {
105
106
  return {
106
107
  content: "",
107
- contentStream: content,
108
+ contentStream: (0, import_utils2.injectServerDataStream)(content, ctx),
108
109
  contentType: import_utils.mime.contentType("html")
109
110
  };
110
111
  }
@@ -0,0 +1,47 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var utils_exports = {};
19
+ __export(utils_exports, {
20
+ injectServerDataStream: () => injectServerDataStream,
21
+ injectSeverData: () => injectSeverData
22
+ });
23
+ module.exports = __toCommonJS(utils_exports);
24
+ var import_template = require("../hook-api/template");
25
+ const injectSeverData = (content, context) => {
26
+ const template = new import_template.TemplateAPI(content);
27
+ template.prependHead(
28
+ `<script>window._SERVER_DATA=${JSON.stringify(
29
+ context.serverData
30
+ )}</script>`
31
+ );
32
+ return template.get();
33
+ };
34
+ const injectServerDataStream = (content, context) => {
35
+ return content.pipe(
36
+ (0, import_template.templateInjectableStream)({
37
+ prependHead: `<script>window._SERVER_DATA=${JSON.stringify(
38
+ context.serverData
39
+ )}</script>`
40
+ })
41
+ );
42
+ };
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ injectServerDataStream,
46
+ injectSeverData
47
+ });
@@ -31,7 +31,6 @@ __export(server_exports, {
31
31
  });
32
32
  module.exports = __toCommonJS(server_exports);
33
33
  var import_path = __toESM(require("path"));
34
- var import_fs = __toESM(require("fs"));
35
34
  var import_utils = require("@modern-js/utils");
36
35
  var import_server_core = require("@modern-js/server-core");
37
36
  var import_metrics = require("../libs/metrics");
@@ -64,7 +63,7 @@ class Server {
64
63
  */
65
64
  async init() {
66
65
  const { options } = this;
67
- this.loadServerEnv(options);
66
+ await this.loadServerEnv(options);
68
67
  this.initServerConfig(options);
69
68
  await this.injectContext(this.runner, options);
70
69
  this.runner = await this.createHookRunner();
@@ -185,13 +184,16 @@ class Server {
185
184
  plugins: serverPlugins
186
185
  };
187
186
  }
188
- loadServerEnv(options) {
187
+ async loadServerEnv(options) {
189
188
  const { pwd: appDirectory } = options;
190
189
  const serverEnv = process.env.MODERN_ENV;
190
+ const defaultEnvPath = import_path.default.resolve(appDirectory, `.env`);
191
191
  const serverEnvPath = import_path.default.resolve(appDirectory, `.env.${serverEnv}`);
192
- if (serverEnv && import_fs.default.existsSync(serverEnvPath) && !import_fs.default.statSync(serverEnvPath).isDirectory()) {
193
- const envConfig = import_utils.dotenv.config({ path: serverEnvPath });
194
- (0, import_utils.dotenvExpand)(envConfig);
192
+ for (const envPath of [serverEnvPath, defaultEnvPath]) {
193
+ if (await import_utils.fs.pathExists(envPath) && !(await import_utils.fs.stat(envPath)).isDirectory()) {
194
+ const envConfig = import_utils.dotenv.config({ path: envPath });
195
+ (0, import_utils.dotenvExpand)(envConfig);
196
+ }
195
197
  }
196
198
  }
197
199
  }
@@ -40,7 +40,6 @@ var import_utils2 = require("../utils");
40
40
  var reader = __toESM(require("../libs/render/reader"));
41
41
  var import_proxy = require("../libs/proxy");
42
42
  var import_context = require("../libs/context");
43
- var import_template = require("../libs/hook-api/template");
44
43
  var import_constants = require("../constants");
45
44
  var import_hook_api = require("../libs/hook-api");
46
45
  const SERVER_DIR = "./server";
@@ -57,7 +56,7 @@ class ModernServer {
57
56
  }) {
58
57
  this.handlers = [];
59
58
  this.reader = reader;
60
- this.beforeRouteHandler = null;
59
+ this.loaderHandler = null;
61
60
  this.frameWebHandler = null;
62
61
  this.frameAPIHandler = null;
63
62
  this.proxyHandler = null;
@@ -95,7 +94,7 @@ class ModernServer {
95
94
  this.router.reset(usageRoutes);
96
95
  this.warmupSSRBundle();
97
96
  await this.prepareFrameHandler();
98
- await this.prepareBeforeRouteHandler(usageRoutes, distDir);
97
+ await this.prepareLoaderHandler(usageRoutes, distDir);
99
98
  const ssrConfig = (_b = this.conf.server) == null ? void 0 : _b.ssr;
100
99
  const forceCSR = typeof ssrConfig === "object" ? ssrConfig.forceCSR : false;
101
100
  this.routeRenderHandler = (0, import_render.createRenderHandler)({
@@ -106,24 +105,12 @@ class ModernServer {
106
105
  await this.setupBeforeProdMiddleware();
107
106
  this.addHandler(this.setupStaticMiddleware((_c = this.conf.output) == null ? void 0 : _c.assetPrefix));
108
107
  this.addHandler(import_serveFile.faviconFallbackHandler);
109
- this.addBeforeRouteHandler();
110
108
  this.addHandler(this.routeHandler.bind(this));
111
109
  this.compose();
112
110
  }
113
111
  // server ready
114
112
  onRepack(_) {
115
113
  }
116
- addBeforeRouteHandler() {
117
- this.addHandler(async (context, next) => {
118
- if (this.beforeRouteHandler) {
119
- await this.beforeRouteHandler(context);
120
- if (this.isSend(context.res)) {
121
- return;
122
- }
123
- }
124
- return next();
125
- });
126
- }
127
114
  onServerChange({ filepath }) {
128
115
  const { pwd } = this;
129
116
  const { api, server } = import_constants.AGGRED_DIR;
@@ -150,6 +137,9 @@ class ModernServer {
150
137
  if (!result) {
151
138
  return null;
152
139
  }
140
+ if (result.contentStream) {
141
+ return result.contentStream;
142
+ }
153
143
  return result.content.toString();
154
144
  }
155
145
  async createHTTPServer(handler) {
@@ -178,9 +168,9 @@ class ModernServer {
178
168
  context.error(import_constants.ERROR_DIGEST.ENOTF, "404 Not Found");
179
169
  this.renderErrorPage(context, 404);
180
170
  }
181
- async prepareBeforeRouteHandler(specs, distDir) {
171
+ async prepareLoaderHandler(specs, distDir) {
182
172
  const { runner } = this;
183
- const handler = await runner.preparebeforeRouteHandler(
173
+ const handler = await runner.prepareLoaderHandler(
184
174
  {
185
175
  serverRoutes: specs,
186
176
  distDir
@@ -189,7 +179,7 @@ class ModernServer {
189
179
  onLast: () => null
190
180
  }
191
181
  );
192
- this.beforeRouteHandler = handler;
182
+ this.loaderHandler = handler;
193
183
  }
194
184
  // gather frame extension and get framework handler
195
185
  async prepareFrameHandler(options) {
@@ -275,11 +265,48 @@ class ModernServer {
275
265
  await this.frameAPIHandler(req, res);
276
266
  }
277
267
  async handleWeb(context, route) {
278
- return this.routeRenderHandler({
268
+ const { res } = context;
269
+ if (this.loaderHandler) {
270
+ await this.loaderHandler(context);
271
+ if (this.isSend(res)) {
272
+ return null;
273
+ }
274
+ }
275
+ context.setParams(route.params);
276
+ context.setServerData("router", {
277
+ baseUrl: route.urlPath,
278
+ params: route.params
279
+ });
280
+ if (route.responseHeaders) {
281
+ Object.keys(route.responseHeaders).forEach((key) => {
282
+ const value = route.responseHeaders[key];
283
+ if (value) {
284
+ context.res.setHeader(key, value);
285
+ }
286
+ });
287
+ }
288
+ const renderResult = await this.routeRenderHandler({
279
289
  ctx: context,
280
290
  route,
281
291
  runner: this.runner
282
292
  });
293
+ if (!renderResult) {
294
+ this.render404(context);
295
+ return null;
296
+ }
297
+ if (renderResult.redirect) {
298
+ this.redirect(
299
+ res,
300
+ renderResult.content,
301
+ renderResult.statusCode
302
+ );
303
+ return null;
304
+ }
305
+ if (this.isSend(res)) {
306
+ return null;
307
+ }
308
+ res.setHeader("content-type", renderResult.contentType);
309
+ return renderResult;
283
310
  }
284
311
  async proxy() {
285
312
  return null;
@@ -312,31 +339,31 @@ class ModernServer {
312
339
  await this.handleAPI(context);
313
340
  return;
314
341
  }
315
- const afterMatchContext = (0, import_hook_api.createAfterMatchContext)(context, route.entryName);
316
- if (this.runMode === import_constants.RUN_MODE.FULL) {
317
- await this.runner.afterMatch(afterMatchContext, { onLast: import_utils2.noop });
318
- }
319
- if (this.isSend(res)) {
320
- return;
321
- }
322
- const { current, url, status } = afterMatchContext.router;
323
- if (url) {
324
- this.redirect(res, url, status);
325
- return;
326
- }
327
- if (route.entryName !== current) {
328
- const matched2 = this.router.matchEntry(current);
329
- if (!matched2) {
330
- this.render404(context);
342
+ if (route.entryName) {
343
+ const afterMatchContext = (0, import_hook_api.createAfterMatchContext)(
344
+ context,
345
+ route.entryName
346
+ );
347
+ if (this.runMode === import_constants.RUN_MODE.FULL) {
348
+ await this.runner.afterMatch(afterMatchContext, { onLast: import_utils2.noop });
349
+ }
350
+ if (this.isSend(res)) {
331
351
  return;
332
352
  }
333
- route = matched2.generate(context.url);
353
+ const { current, url, status } = afterMatchContext.router;
354
+ if (url) {
355
+ this.redirect(res, url, status);
356
+ return;
357
+ }
358
+ if (route.entryName !== current) {
359
+ const matched2 = this.router.matchEntry(current);
360
+ if (!matched2) {
361
+ this.render404(context);
362
+ return;
363
+ }
364
+ route = matched2.generate(context.url);
365
+ }
334
366
  }
335
- context.setParams(route.params);
336
- context.setServerData("router", {
337
- baseUrl: route.urlPath,
338
- params: route.params
339
- });
340
367
  if (this.frameWebHandler) {
341
368
  res.locals = res.locals || {};
342
369
  const middlewareContext = (0, import_hook_api.createMiddlewareContext)(context);
@@ -345,47 +372,20 @@ class ModernServer {
345
372
  ...res.locals,
346
373
  ...middlewareContext.response.locals
347
374
  };
348
- }
349
- if (this.isSend(res)) {
350
- return;
351
- }
352
- if (route.responseHeaders) {
353
- Object.keys(route.responseHeaders).forEach((key) => {
354
- const value = route.responseHeaders[key];
355
- if (value) {
356
- context.res.setHeader(key, value);
357
- }
358
- });
375
+ if (this.isSend(res)) {
376
+ return;
377
+ }
359
378
  }
360
379
  const renderResult = await this.handleWeb(context, route);
361
380
  if (!renderResult) {
362
- this.render404(context);
363
- return;
364
- }
365
- if (renderResult.redirect) {
366
- this.redirect(
367
- res,
368
- renderResult.content,
369
- renderResult.statusCode
370
- );
371
381
  return;
372
382
  }
373
- if (this.isSend(res)) {
383
+ const { contentStream: responseStream } = renderResult;
384
+ let { content: response } = renderResult;
385
+ if (route.entryName && responseStream) {
386
+ responseStream.pipe(res);
374
387
  return;
375
388
  }
376
- res.setHeader("content-type", renderResult.contentType);
377
- const { contentStream } = renderResult;
378
- if (contentStream) {
379
- contentStream.pipe(
380
- (0, import_template.templateInjectableStream)({
381
- prependHead: route.entryName ? `<script>window._SERVER_DATA=${JSON.stringify(
382
- context.serverData
383
- )}</script>` : void 0
384
- })
385
- ).pipe(res);
386
- return;
387
- }
388
- let response = renderResult.content;
389
389
  if (route.entryName) {
390
390
  const afterRenderContext = (0, import_hook_api.createAfterRenderContext)(
391
391
  context,
@@ -397,11 +397,6 @@ class ModernServer {
397
397
  if (this.isSend(res)) {
398
398
  return;
399
399
  }
400
- afterRenderContext.template.prependHead(
401
- `<script>window._SERVER_DATA=${JSON.stringify(
402
- context.serverData
403
- )}</script>`
404
- );
405
400
  response = afterRenderContext.template.get();
406
401
  }
407
402
  res.end(response);
@@ -124,15 +124,10 @@ var Response = /*#__PURE__*/ function() {
124
124
  _classCallCheck(this, Response);
125
125
  _defineProperty(this, "cookies", void 0);
126
126
  _defineProperty(this, "res", void 0);
127
- _defineProperty(this, "_cookie", void 0);
128
127
  this.res = res;
129
- this._cookie = cookie.parse(res.getHeader("set-cookie") || "");
130
128
  this.cookies = {
131
- get: this.getCookie.bind(this),
132
129
  set: this.setCookie.bind(this),
133
- delete: this.deleteCookie.bind(this),
134
- clear: this.clearCookie.bind(this),
135
- apply: this.applyCookie.bind(this)
130
+ clear: this.clearCookie.bind(this)
136
131
  };
137
132
  }
138
133
  _createClass(Response, [
@@ -154,44 +149,21 @@ var Response = /*#__PURE__*/ function() {
154
149
  this.res.statusCode = code;
155
150
  }
156
151
  },
157
- {
158
- key: "getCookie",
159
- value: function getCookie(key) {
160
- return this._cookie[key];
161
- }
162
- },
163
152
  {
164
153
  key: "setCookie",
165
- value: function setCookie(key, value) {
166
- this._cookie[key] = value;
167
- }
168
- },
169
- {
170
- key: "deleteCookie",
171
- value: function deleteCookie(key) {
172
- if (this._cookie[key]) {
173
- delete this._cookie[key];
174
- }
154
+ value: function setCookie(key, value, options) {
155
+ var cookieValue = this.res.getHeader("set-cookie");
156
+ var fmt = Array.isArray(cookieValue) ? cookieValue : [
157
+ cookieValue
158
+ ].filter(Boolean);
159
+ fmt.push(cookie.serialize(key, value, options));
160
+ this.res.setHeader("set-cookie", fmt.length === 1 ? fmt[0] : fmt);
175
161
  }
176
162
  },
177
163
  {
178
164
  key: "clearCookie",
179
165
  value: function clearCookie() {
180
- this._cookie = {};
181
- }
182
- },
183
- {
184
- key: "applyCookie",
185
- value: function applyCookie() {
186
- var str = Object.entries(this._cookie).map(function(param) {
187
- var _param = _slicedToArray(param, 2), key = _param[0], value = _param[1];
188
- return cookie.serialize(key, value);
189
- }).join("; ");
190
- if (str) {
191
- this.res.setHeader("set-cookie", str);
192
- } else {
193
- this.res.removeHeader("set-cookie");
194
- }
166
+ this.res.removeHeader("set-cookie");
195
167
  }
196
168
  },
197
169
  {
@@ -128,6 +128,7 @@ import { ERROR_DIGEST } from "../../constants";
128
128
  import { handleDirectory } from "./static";
129
129
  import { readFile } from "./reader";
130
130
  import * as ssr from "./ssr";
131
+ import { injectSeverData } from "./utils";
131
132
  var createRenderHandler = function(param) {
132
133
  var distDir = param.distDir, staticGenerate = param.staticGenerate, forceCSR = param.forceCSR;
133
134
  return function() {
@@ -218,7 +219,7 @@ var createRenderHandler = function(param) {
218
219
  return [
219
220
  2,
220
221
  {
221
- content: content,
222
+ content: route.entryName ? injectSeverData(content.toString(), ctx) : content,
222
223
  contentType: mime.contentType(path.extname(templatePath))
223
224
  }
224
225
  ];
@@ -126,6 +126,7 @@ import path from "path";
126
126
  import { fs, LOADABLE_STATS_FILE, mime, ROUTE_MINIFEST_FILE, SERVER_RENDER_FUNCTION_NAME } from "@modern-js/utils";
127
127
  import cache from "./cache";
128
128
  import { createLogger, createMetrics } from "./measure";
129
+ import { injectServerDataStream, injectSeverData } from "./utils";
129
130
  var render = function() {
130
131
  var _ref = _asyncToGenerator(function(ctx, renderOptions, runner) {
131
132
  var _ctx_res, urlPath, bundle, distDir, template, entryName, staticGenerate, _renderOptions_enableUnsafeCtx, enableUnsafeCtx, bundleJS, loadableUri, loadableStats, routesManifestUri, routeManifest, context, serverRender, content, _context_redirection, url, _context_redirection_status, status;
@@ -196,7 +197,7 @@ var render = function() {
196
197
  return [
197
198
  2,
198
199
  {
199
- content: content,
200
+ content: injectSeverData(content, ctx),
200
201
  contentType: mime.contentType("html")
201
202
  }
202
203
  ];
@@ -205,7 +206,7 @@ var render = function() {
205
206
  2,
206
207
  {
207
208
  content: "",
208
- contentStream: content,
209
+ contentStream: injectServerDataStream(content, ctx),
209
210
  contentType: mime.contentType("html")
210
211
  }
211
212
  ];
@@ -0,0 +1,12 @@
1
+ import { TemplateAPI, templateInjectableStream } from "../hook-api/template";
2
+ var injectSeverData = function(content, context) {
3
+ var template = new TemplateAPI(content);
4
+ template.prependHead("<script>window._SERVER_DATA=".concat(JSON.stringify(context.serverData), "</script>"));
5
+ return template.get();
6
+ };
7
+ var injectServerDataStream = function(content, context) {
8
+ return content.pipe(templateInjectableStream({
9
+ prependHead: "<script>window._SERVER_DATA=".concat(JSON.stringify(context.serverData), "</script>")
10
+ }));
11
+ };
12
+ export { injectServerDataStream, injectSeverData };