vite-plugin-blocklet 0.8.2 → 0.8.4

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/dist/index.cjs CHANGED
@@ -26,12 +26,15 @@ function toBlockletDid(name) {
26
26
  }
27
27
 
28
28
  const isInBlocklet = !!process.env.BLOCKLET_PORT;
29
+ const blockletPort = process.env.BLOCKLET_PORT;
30
+ const blockletPrefix = process.env.BLOCKLET_DEV_MOUNT_POINT || '/';
29
31
 
30
32
  /**
31
33
  * Creates a HMR plugin with the given options.
32
34
  *
33
35
  * @param {Object} options - The options for the HMR plugin.
34
36
  * @param {string} options.version - The version of the vite version.
37
+ * @param {'middleware'|'client'} options.hmrMode - The version of the vite version.
35
38
  * @return {Object} The HMR plugin object.
36
39
  */
37
40
  function createHmrPlugin(options = {}) {
@@ -39,7 +42,7 @@ function createHmrPlugin(options = {}) {
39
42
  return {
40
43
  name: 'blocklet:hmr',
41
44
  apply: 'serve',
42
- async transform(code, id) {
45
+ transform(code, id) {
43
46
  if (isInBlocklet && id.endsWith('/vite/dist/client/client.mjs')) {
44
47
  const pureVersion = semver.major(version);
45
48
  let replacedCode = code;
@@ -52,29 +55,35 @@ function createHmrPlugin(options = {}) {
52
55
  return replacedCode;
53
56
  }
54
57
 
55
- // 根据页面的协议自动判断端口
56
- replacedCode = replacedCode.replace(
57
- /__HMR_PORT__/g,
58
- 'location.port || (location.protocol === "https:" ? 443 : 80);',
59
- );
60
-
61
- // 在页面加载时,触发一次 upgrade
62
- replacedCode = replacedCode.replace(
63
- 'function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {',
64
- 'async function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {\nawait waitForSuccessfulPing(protocol, hostAndPath);\n',
65
- );
66
- replacedCode = replacedCode.replace('fallback = () => {', 'fallback = async () => {');
67
- replacedCode = replacedCode.replace(/socket = setupWebSocket\(/g, 'socket = await setupWebSocket(');
68
-
69
- if ([4, 5].includes(pureVersion)) {
70
- // 改变刷新页面的判断
58
+ replacedCode = replacedCode.replace(/__HMR_BASE__/g, `"${blockletPrefix}"+__HMR_BASE__`);
59
+
60
+ if (process.env.VITE_HMR_MODE === 'middleware') {
61
+ // 根据页面的协议自动判断端口
62
+ replacedCode = replacedCode.replace(
63
+ /__HMR_PORT__/g,
64
+ 'location.port || (location.protocol === "https:" ? 443 : 80);',
65
+ );
66
+
67
+ // 在页面加载时,触发一次 upgrade
71
68
  replacedCode = replacedCode.replace(
72
- 'const ping =',
73
- "const ping = async () => {\ntry {\nawait fetch(`${pingHostProtocol}://${hostAndPath}`, {\nmode: 'no-cors',\nheaders: {\nAccept: 'text/x-vite-ping'\n}\n}).then(res => {\nif ([404, 502].includes(res.status)) {\nthrow new Error('waiting for server to restart...');\n}\n});\nreturn true;\n} catch {}\nreturn false;\n}\nconst pingBak =",
69
+ 'function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {',
70
+ 'async function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {\nawait waitForSuccessfulPing(protocol, hostAndPath);\n',
74
71
  );
72
+ replacedCode = replacedCode.replace('fallback = () => {', 'fallback = async () => {');
73
+ replacedCode = replacedCode.replace(/socket = setupWebSocket\(/g, 'socket = await setupWebSocket(');
74
+
75
+ if ([4, 5].includes(pureVersion)) {
76
+ // 改变刷新页面的判断
77
+ replacedCode = replacedCode.replace(
78
+ 'const ping =',
79
+ "const ping = async () => {\ntry {\nawait fetch(`${pingHostProtocol}://${hostAndPath}`, {\nmode: 'no-cors',\nheaders: {\nAccept: 'text/x-vite-ping'\n}\n}).then(res => {\nif ([404, 502].includes(res.status)) {\nthrow new Error('waiting for server to restart...');\n}\n});\nreturn true;\n} catch {}\nreturn false;\n}\nconst pingBak =",
80
+ );
81
+ }
75
82
  }
83
+
76
84
  return replacedCode;
77
85
  }
86
+ return code;
78
87
  },
79
88
  };
80
89
  }
@@ -85,10 +94,9 @@ function createConfigPlugin$1() {
85
94
  configureServer(server) {
86
95
  if (isInBlocklet) {
87
96
  server.middlewares.use((req, res, next) => {
88
- const prefix = req.headers['x-path-prefix'] || '/';
89
97
  // blocklet server 会把设置的 base 从请求 url 中移除,所以需要再加回 base
90
- if (!req.url.startsWith(prefix)) {
91
- req.url = path.join(prefix || '/', req.url);
98
+ if (!req.url.startsWith(blockletPrefix)) {
99
+ req.url = path.join(blockletPrefix || '/', req.url);
92
100
  }
93
101
  return next();
94
102
  });
@@ -97,21 +105,9 @@ function createConfigPlugin$1() {
97
105
  config(config, { command }) {
98
106
  if (command === 'serve') {
99
107
  const targetConfig = {};
100
- if (!config.base) {
101
- let base = process.env.BLOCKLET_DEV_MOUNT_POINT || '';
102
-
103
- if (base) {
104
- if (!base.startsWith('/')) {
105
- base = `/${base}`;
106
- }
107
- if (!base.endsWith('/')) {
108
- base = `${base}/`;
109
- }
110
- }
111
- targetConfig.base = base;
112
- }
108
+ targetConfig.base = path.join('/', config.base || blockletPrefix, '/');
113
109
  if (!(config.server && config.server.port)) {
114
- const port = process.env.BLOCKLET_PORT || 3000;
110
+ const port = blockletPort || 3000;
115
111
  targetConfig.server = {
116
112
  port,
117
113
  };
@@ -404,6 +400,52 @@ function createConfigPlugin(options) {
404
400
  };
405
401
  }
406
402
 
403
+ /**
404
+ * Creates a config plugin for Vite development server.
405
+ *
406
+ * @param {object} options - The options for the plugin.
407
+ * @param {string} options.entryPath - The entry path of the Express app.
408
+ * @param {array} options.ignorePath - The entry path of the Express app.
409
+ * @return {object} The Vite config plugin.
410
+ */
411
+ function createExpressPlugin({ entryPath, ignorePath = [] }) {
412
+ ignorePath = Array.isArray(ignorePath) ? ignorePath : [ignorePath];
413
+ // 此处需要解构 import.meta 对象,才能拿到 vite.config 的地址,否则拿到的地址会是 express.js 文件的地址
414
+ return {
415
+ name: 'blocklet:express',
416
+ apply: 'serve',
417
+ configureServer(server) {
418
+ server.middlewares.use(async (req, res, next) => {
419
+ process.env.VITE = 'true';
420
+ try {
421
+ const { app } = await server.ssrLoadModule(entryPath);
422
+ app(req, res, next);
423
+ } catch (err) {
424
+ console.error(err);
425
+ }
426
+ });
427
+ },
428
+ handleHotUpdate({ server, modules, timestamp }) {
429
+ const validatedModules = [];
430
+ const invalidatedModules = [];
431
+
432
+ for (const mod of modules) {
433
+ if (ignorePath.some((x) => mod.file.startsWith(x))) {
434
+ invalidatedModules.push(mod);
435
+ } else {
436
+ validatedModules.push(mod);
437
+ }
438
+ }
439
+ // 手动使模块失效
440
+ const mods = new Set();
441
+ for (const mod of invalidatedModules) {
442
+ server.moduleGraph.invalidateModule(mod, mods, timestamp, true);
443
+ }
444
+ return validatedModules;
445
+ },
446
+ };
447
+ }
448
+
407
449
  const argv = process.argv.slice(2);
408
450
  const isProduction = process.env.NODE_ENV === 'production' || process.env.ABT_NODE_SERVICE_ENV === 'production';
409
451
 
@@ -433,7 +475,8 @@ async function setupClient(app, options = {}) {
433
475
  target: `ws://127.0.0.1:${port}`,
434
476
  ws: true,
435
477
  });
436
- app.use('/__vite_hmr__', wsProxy);
478
+ process.env.VITE_HMR_MODE = 'middleware';
479
+ app.use(path.join(blockletPrefix, '/__vite_hmr__'), wsProxy);
437
480
 
438
481
  // 以中间件模式创建 Vite 服务器
439
482
  const vite$1 = await vite.createServer({
@@ -442,7 +485,6 @@ async function setupClient(app, options = {}) {
442
485
  middlewareMode: true,
443
486
  hmr: {
444
487
  port,
445
- clientPort: 80,
446
488
  path: '/__vite_hmr__',
447
489
  },
448
490
  },
@@ -464,12 +506,14 @@ async function setupClient(app, options = {}) {
464
506
  * @property {boolean} [disableHmr=false] - Disable hmr plugin.
465
507
  * @property {boolean} [disableLoading=false] - Disable loading plugin.
466
508
  * @property {boolean} [disableDebug=false] - Disable debug plugin.
509
+ * @property {import('vite-plugin-node-polyfills').PolyfillOptions} [nodePolyfillsOptions]
467
510
  *
468
511
  * @property {string} [loadingElementId]
469
512
  * @property {string} [loadingColor]
470
513
  * @property {string} [loadingImage]
471
514
  * @property {'all'|'mobile'|'desktop'} [debugPlatform='mobile']
472
515
  * @property {string} [debugScript]
516
+ * @property {'middleware'|'client'} [hmrMode='middleware']
473
517
  */
474
518
 
475
519
  /**
@@ -488,6 +532,7 @@ function createBlockletPlugin(options = {}) {
488
532
  disableHmr = false,
489
533
  disableLoading = false,
490
534
  disableDebug = false,
535
+ nodePolyfillsOptions,
491
536
  ...restOptions
492
537
  } = options;
493
538
 
@@ -504,7 +549,7 @@ function createBlockletPlugin(options = {}) {
504
549
  plugins.push(createHmrPlugin(restOptions));
505
550
  }
506
551
  if (!disableNodePolyfills) {
507
- plugins.push(vitePluginNodePolyfills.nodePolyfills({ protocolImports: true }));
552
+ plugins.push(vitePluginNodePolyfills.nodePolyfills(nodePolyfillsOptions));
508
553
  }
509
554
  if (!disableLoading) {
510
555
  plugins.push(createLoadingPlugin(restOptions));
@@ -522,6 +567,7 @@ Object.defineProperty(exports, "nodePolyfills", {
522
567
  });
523
568
  exports.createBlockletConfig = createConfigPlugin$1;
524
569
  exports.createBlockletDebug = createConfigPlugin;
570
+ exports.createBlockletExpress = createExpressPlugin;
525
571
  exports.createBlockletHmr = createHmrPlugin;
526
572
  exports.createBlockletLoading = createLoadingPlugin;
527
573
  exports.createBlockletMeta = createMetaPlugin;
package/index.js CHANGED
@@ -4,6 +4,7 @@ import createConfigPlugin from './libs/config.js';
4
4
  import createMetaPlugin from './libs/meta.js';
5
5
  import createLoadingPlugin from './libs/loading.js';
6
6
  import createDebugPlugin from './libs/debug.js';
7
+ import createExpressPlugin from './libs/express.js';
7
8
  import setupClient from './libs/client.js';
8
9
 
9
10
  /**
@@ -16,12 +17,14 @@ import setupClient from './libs/client.js';
16
17
  * @property {boolean} [disableHmr=false] - Disable hmr plugin.
17
18
  * @property {boolean} [disableLoading=false] - Disable loading plugin.
18
19
  * @property {boolean} [disableDebug=false] - Disable debug plugin.
20
+ * @property {import('vite-plugin-node-polyfills').PolyfillOptions} [nodePolyfillsOptions]
19
21
  *
20
22
  * @property {string} [loadingElementId]
21
23
  * @property {string} [loadingColor]
22
24
  * @property {string} [loadingImage]
23
25
  * @property {'all'|'mobile'|'desktop'} [debugPlatform='mobile']
24
26
  * @property {string} [debugScript]
27
+ * @property {'middleware'|'client'} [hmrMode='middleware']
25
28
  */
26
29
 
27
30
  /**
@@ -40,6 +43,7 @@ export function createBlockletPlugin(options = {}) {
40
43
  disableHmr = false,
41
44
  disableLoading = false,
42
45
  disableDebug = false,
46
+ nodePolyfillsOptions,
43
47
  ...restOptions
44
48
  } = options;
45
49
 
@@ -56,7 +60,7 @@ export function createBlockletPlugin(options = {}) {
56
60
  plugins.push(createHmrPlugin(restOptions));
57
61
  }
58
62
  if (!disableNodePolyfills) {
59
- plugins.push(nodePolyfills({ protocolImports: true }));
63
+ plugins.push(nodePolyfills(nodePolyfillsOptions));
60
64
  }
61
65
  if (!disableLoading) {
62
66
  plugins.push(createLoadingPlugin(restOptions));
@@ -75,5 +79,6 @@ export {
75
79
  createMetaPlugin as createBlockletMeta,
76
80
  createLoadingPlugin as createBlockletLoading,
77
81
  createDebugPlugin as createBlockletDebug,
82
+ createExpressPlugin as createBlockletExpress,
78
83
  nodePolyfills,
79
84
  };
package/libs/client.js CHANGED
@@ -1,7 +1,9 @@
1
+ import path from 'node:path';
1
2
  import getPort from 'get-port';
2
3
  import { createServer } from 'vite';
3
4
  import mri from 'mri';
4
5
  import { createProxyMiddleware } from 'http-proxy-middleware';
6
+ import { blockletPrefix } from './utils.js';
5
7
 
6
8
  const argv = process.argv.slice(2);
7
9
  const isProduction = process.env.NODE_ENV === 'production' || process.env.ABT_NODE_SERVICE_ENV === 'production';
@@ -32,7 +34,8 @@ export default async function setupClient(app, options = {}) {
32
34
  target: `ws://127.0.0.1:${port}`,
33
35
  ws: true,
34
36
  });
35
- app.use('/__vite_hmr__', wsProxy);
37
+ process.env.VITE_HMR_MODE = 'middleware';
38
+ app.use(path.join(blockletPrefix, '/__vite_hmr__'), wsProxy);
36
39
 
37
40
  // 以中间件模式创建 Vite 服务器
38
41
  const vite = await createServer({
@@ -41,7 +44,6 @@ export default async function setupClient(app, options = {}) {
41
44
  middlewareMode: true,
42
45
  hmr: {
43
46
  port,
44
- clientPort: 80,
45
47
  path: '/__vite_hmr__',
46
48
  },
47
49
  },
package/libs/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import YAML from 'yaml';
4
- import { toBlockletDid, isInBlocklet } from './utils.js';
4
+ import { toBlockletDid, isInBlocklet, blockletPort, blockletPrefix } from './utils.js';
5
5
 
6
6
  export default function createConfigPlugin() {
7
7
  return {
@@ -9,10 +9,9 @@ export default function createConfigPlugin() {
9
9
  configureServer(server) {
10
10
  if (isInBlocklet) {
11
11
  server.middlewares.use((req, res, next) => {
12
- const prefix = req.headers['x-path-prefix'] || '/';
13
12
  // blocklet server 会把设置的 base 从请求 url 中移除,所以需要再加回 base
14
- if (!req.url.startsWith(prefix)) {
15
- req.url = path.join(prefix || '/', req.url);
13
+ if (!req.url.startsWith(blockletPrefix)) {
14
+ req.url = path.join(blockletPrefix || '/', req.url);
16
15
  }
17
16
  return next();
18
17
  });
@@ -21,21 +20,9 @@ export default function createConfigPlugin() {
21
20
  config(config, { command }) {
22
21
  if (command === 'serve') {
23
22
  const targetConfig = {};
24
- if (!config.base) {
25
- let base = process.env.BLOCKLET_DEV_MOUNT_POINT || '';
26
-
27
- if (base) {
28
- if (!base.startsWith('/')) {
29
- base = `/${base}`;
30
- }
31
- if (!base.endsWith('/')) {
32
- base = `${base}/`;
33
- }
34
- }
35
- targetConfig.base = base;
36
- }
23
+ targetConfig.base = path.join('/', config.base || blockletPrefix, '/');
37
24
  if (!(config.server && config.server.port)) {
38
- const port = process.env.BLOCKLET_PORT || 3000;
25
+ const port = blockletPort || 3000;
39
26
  targetConfig.server = {
40
27
  port,
41
28
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Creates a config plugin for Vite development server.
3
+ *
4
+ * @param {object} options - The options for the plugin.
5
+ * @param {string} options.entryPath - The entry path of the Express app.
6
+ * @param {array} options.ignorePath - The entry path of the Express app.
7
+ * @return {object} The Vite config plugin.
8
+ */
9
+ export default function createExpressPlugin({ entryPath, ignorePath = [] }) {
10
+ ignorePath = Array.isArray(ignorePath) ? ignorePath : [ignorePath];
11
+ // 此处需要解构 import.meta 对象,才能拿到 vite.config 的地址,否则拿到的地址会是 express.js 文件的地址
12
+ return {
13
+ name: 'blocklet:express',
14
+ apply: 'serve',
15
+ configureServer(server) {
16
+ server.middlewares.use(async (req, res, next) => {
17
+ process.env.VITE = 'true';
18
+ try {
19
+ const { app } = await server.ssrLoadModule(entryPath);
20
+ app(req, res, next);
21
+ } catch (err) {
22
+ console.error(err);
23
+ }
24
+ });
25
+ },
26
+ handleHotUpdate({ server, modules, timestamp }) {
27
+ const validatedModules = [];
28
+ const invalidatedModules = [];
29
+
30
+ for (const mod of modules) {
31
+ if (ignorePath.some((x) => mod.file.startsWith(x))) {
32
+ invalidatedModules.push(mod);
33
+ } else {
34
+ validatedModules.push(mod);
35
+ }
36
+ }
37
+ // 手动使模块失效
38
+ const mods = new Set();
39
+ for (const mod of invalidatedModules) {
40
+ server.moduleGraph.invalidateModule(mod, mods, timestamp, true);
41
+ }
42
+ return validatedModules;
43
+ },
44
+ };
45
+ }
package/libs/hmr.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { version as viteVersion } from 'vite';
2
2
  import semver from 'semver';
3
- import { isInBlocklet } from './utils.js';
3
+ import { blockletPrefix, isInBlocklet } from './utils.js';
4
4
 
5
5
  /**
6
6
  * Creates a HMR plugin with the given options.
7
7
  *
8
8
  * @param {Object} options - The options for the HMR plugin.
9
9
  * @param {string} options.version - The version of the vite version.
10
+ * @param {'middleware'|'client'} options.hmrMode - The version of the vite version.
10
11
  * @return {Object} The HMR plugin object.
11
12
  */
12
13
  export default function createHmrPlugin(options = {}) {
@@ -14,7 +15,7 @@ export default function createHmrPlugin(options = {}) {
14
15
  return {
15
16
  name: 'blocklet:hmr',
16
17
  apply: 'serve',
17
- async transform(code, id) {
18
+ transform(code, id) {
18
19
  if (isInBlocklet && id.endsWith('/vite/dist/client/client.mjs')) {
19
20
  const pureVersion = semver.major(version);
20
21
  let replacedCode = code;
@@ -27,29 +28,35 @@ export default function createHmrPlugin(options = {}) {
27
28
  return replacedCode;
28
29
  }
29
30
 
30
- // 根据页面的协议自动判断端口
31
- replacedCode = replacedCode.replace(
32
- /__HMR_PORT__/g,
33
- 'location.port || (location.protocol === "https:" ? 443 : 80);',
34
- );
31
+ replacedCode = replacedCode.replace(/__HMR_BASE__/g, `"${blockletPrefix}"+__HMR_BASE__`);
35
32
 
36
- // 在页面加载时,触发一次 upgrade
37
- replacedCode = replacedCode.replace(
38
- 'function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {',
39
- 'async function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {\nawait waitForSuccessfulPing(protocol, hostAndPath);\n',
40
- );
41
- replacedCode = replacedCode.replace('fallback = () => {', 'fallback = async () => {');
42
- replacedCode = replacedCode.replace(/socket = setupWebSocket\(/g, 'socket = await setupWebSocket(');
33
+ if (process.env.VITE_HMR_MODE === 'middleware') {
34
+ // 根据页面的协议自动判断端口
35
+ replacedCode = replacedCode.replace(
36
+ /__HMR_PORT__/g,
37
+ 'location.port || (location.protocol === "https:" ? 443 : 80);',
38
+ );
43
39
 
44
- if ([4, 5].includes(pureVersion)) {
45
- // 改变刷新页面的判断
40
+ // 在页面加载时,触发一次 upgrade
46
41
  replacedCode = replacedCode.replace(
47
- 'const ping =',
48
- "const ping = async () => {\ntry {\nawait fetch(`${pingHostProtocol}://${hostAndPath}`, {\nmode: 'no-cors',\nheaders: {\nAccept: 'text/x-vite-ping'\n}\n}).then(res => {\nif ([404, 502].includes(res.status)) {\nthrow new Error('waiting for server to restart...');\n}\n});\nreturn true;\n} catch {}\nreturn false;\n}\nconst pingBak =",
42
+ 'function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {',
43
+ 'async function setupWebSocket(protocol, hostAndPath, onCloseWithoutOpen) {\nawait waitForSuccessfulPing(protocol, hostAndPath);\n',
49
44
  );
45
+ replacedCode = replacedCode.replace('fallback = () => {', 'fallback = async () => {');
46
+ replacedCode = replacedCode.replace(/socket = setupWebSocket\(/g, 'socket = await setupWebSocket(');
47
+
48
+ if ([4, 5].includes(pureVersion)) {
49
+ // 改变刷新页面的判断
50
+ replacedCode = replacedCode.replace(
51
+ 'const ping =',
52
+ "const ping = async () => {\ntry {\nawait fetch(`${pingHostProtocol}://${hostAndPath}`, {\nmode: 'no-cors',\nheaders: {\nAccept: 'text/x-vite-ping'\n}\n}).then(res => {\nif ([404, 502].includes(res.status)) {\nthrow new Error('waiting for server to restart...');\n}\n});\nreturn true;\n} catch {}\nreturn false;\n}\nconst pingBak =",
53
+ );
54
+ }
50
55
  }
56
+
51
57
  return replacedCode;
52
58
  }
59
+ return code;
53
60
  },
54
61
  };
55
62
  }
package/libs/utils.js CHANGED
@@ -13,6 +13,6 @@ export function toBlockletDid(name) {
13
13
  return fromPublicKey(pk, { role: types.RoleType.ROLE_ANY });
14
14
  }
15
15
 
16
- const isInBlocklet = !!process.env.BLOCKLET_PORT;
17
-
18
- export { isInBlocklet };
16
+ export const isInBlocklet = !!process.env.BLOCKLET_PORT;
17
+ export const blockletPort = process.env.BLOCKLET_PORT;
18
+ export const blockletPrefix = process.env.BLOCKLET_DEV_MOUNT_POINT || '/';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vite-plugin-blocklet",
3
3
  "type": "module",
4
- "version": "0.8.2",
4
+ "version": "0.8.4",
5
5
  "description": "",
6
6
  "main": "index.js",
7
7
  "files": [