@deot/dev-dever 2.4.0 → 2.5.1

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
@@ -8,6 +8,8 @@ const devShared = require('@deot/dev-shared');
8
8
  const fs$1 = require('fs-extra');
9
9
  const vite = require('vite');
10
10
  const chalk = require('chalk');
11
+ const sharedVueConfig = require('@deot/dev-vue');
12
+ const sharedReactConfig = require('@deot/dev-react');
11
13
  const fs = require('node:fs');
12
14
  const ejs = require('ejs');
13
15
 
@@ -46,7 +48,7 @@ const walk = (dir) => {
46
48
  const paths = fullpath.split("/") || [];
47
49
  const stat = fs__namespace.statSync(fullpath);
48
50
  const extname = path__namespace.extname(fullpath);
49
- if (stat.isFile() && /\.(t|j)sx?$/.test(extname) && paths.length >= 2 && paths[paths.length - 2] === "examples") {
51
+ if (stat.isFile() && /\.((t|j)sx?|vue)$/.test(extname) && paths.length >= 2 && paths[paths.length - 2] === "examples") {
50
52
  const basename = path__namespace.basename(file, extname);
51
53
  let name = path__namespace.join(dir, basename).split("/");
52
54
  name.splice(name.length - 2, 1);
@@ -78,9 +80,8 @@ const run = (options) => devShared.Utils.autoCatch(async () => {
78
80
  }
79
81
  if (options.dryRun)
80
82
  return devShared.Shell.spawn(`echo development`);
81
- const { cwd, workspace, packageOptionsMap, packageDirsMap } = locals;
82
- const { packageName } = options;
83
- const packageFolderName = devShared.Locals.getPackageFolderName(packageName);
83
+ const { cwd, workspace, packageOptionsMap, packageDirsMap, subpackagesMap } = locals;
84
+ const packageFolderName = devShared.Locals.getPackageFolderName(options.packageName);
84
85
  const packageOptions = packageOptionsMap[packageFolderName];
85
86
  const packageDir = packageDirsMap[packageFolderName];
86
87
  options.watch = true;
@@ -94,12 +95,6 @@ const run = (options) => devShared.Utils.autoCatch(async () => {
94
95
  delete options.workspace;
95
96
  delete options.packageName;
96
97
  let { entries, html } = get();
97
- process.env.DEV_OPTIONS = encodeURIComponent(JSON.stringify({
98
- ...options,
99
- workspace,
100
- entries,
101
- html
102
- }));
103
98
  if (!entries.length)
104
99
  return devShared.Shell.spawn(`echo no entry file found!`);
105
100
  let options$ = {
@@ -113,7 +108,21 @@ const run = (options) => devShared.Utils.autoCatch(async () => {
113
108
  options$.configFile = path__namespace.relative(cwd, path__namespace.resolve(cwd, "./dev.config.ts"));
114
109
  } else {
115
110
  options$.configFile = path__namespace.relative(cwd, path__namespace.resolve(dirname, "../shared.config.ts"));
111
+ const { vuePackage, reactPackage } = options;
112
+ if (vuePackage) {
113
+ options$ = vite.mergeConfig(sharedVueConfig, options$);
114
+ }
115
+ if (reactPackage) {
116
+ options$ = vite.mergeConfig(sharedReactConfig, options$);
117
+ }
116
118
  }
119
+ process.env.DEV_OPTIONS = encodeURIComponent(JSON.stringify({
120
+ ...options,
121
+ workspace,
122
+ entries,
123
+ html,
124
+ subpackagesMap
125
+ }));
117
126
  const server = await vite.createServer(options$);
118
127
  const $server = await server.listen();
119
128
  const { local = [], network = [] } = $server.resolvedUrls || {};
package/dist/index.es.js CHANGED
@@ -2,8 +2,10 @@ import * as path from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import { Locals, Utils, Shell, Logger } from '@deot/dev-shared';
4
4
  import fs$1 from 'fs-extra';
5
- import { createServer } from 'vite';
5
+ import { mergeConfig, createServer } from 'vite';
6
6
  import chalk from 'chalk';
7
+ import sharedVueConfig from '@deot/dev-vue';
8
+ import sharedReactConfig from '@deot/dev-react';
7
9
  import * as fs from 'node:fs';
8
10
  import { render } from 'ejs';
9
11
 
@@ -22,7 +24,7 @@ const walk = (dir) => {
22
24
  const paths = fullpath.split("/") || [];
23
25
  const stat = fs.statSync(fullpath);
24
26
  const extname = path.extname(fullpath);
25
- if (stat.isFile() && /\.(t|j)sx?$/.test(extname) && paths.length >= 2 && paths[paths.length - 2] === "examples") {
27
+ if (stat.isFile() && /\.((t|j)sx?|vue)$/.test(extname) && paths.length >= 2 && paths[paths.length - 2] === "examples") {
26
28
  const basename = path.basename(file, extname);
27
29
  let name = path.join(dir, basename).split("/");
28
30
  name.splice(name.length - 2, 1);
@@ -54,9 +56,8 @@ const run = (options) => Utils.autoCatch(async () => {
54
56
  }
55
57
  if (options.dryRun)
56
58
  return Shell.spawn(`echo development`);
57
- const { cwd, workspace, packageOptionsMap, packageDirsMap } = locals;
58
- const { packageName } = options;
59
- const packageFolderName = Locals.getPackageFolderName(packageName);
59
+ const { cwd, workspace, packageOptionsMap, packageDirsMap, subpackagesMap } = locals;
60
+ const packageFolderName = Locals.getPackageFolderName(options.packageName);
60
61
  const packageOptions = packageOptionsMap[packageFolderName];
61
62
  const packageDir = packageDirsMap[packageFolderName];
62
63
  options.watch = true;
@@ -70,12 +71,6 @@ const run = (options) => Utils.autoCatch(async () => {
70
71
  delete options.workspace;
71
72
  delete options.packageName;
72
73
  let { entries, html } = get();
73
- process.env.DEV_OPTIONS = encodeURIComponent(JSON.stringify({
74
- ...options,
75
- workspace,
76
- entries,
77
- html
78
- }));
79
74
  if (!entries.length)
80
75
  return Shell.spawn(`echo no entry file found!`);
81
76
  let options$ = {
@@ -89,7 +84,21 @@ const run = (options) => Utils.autoCatch(async () => {
89
84
  options$.configFile = path.relative(cwd, path.resolve(cwd, "./dev.config.ts"));
90
85
  } else {
91
86
  options$.configFile = path.relative(cwd, path.resolve(dirname, "../shared.config.ts"));
87
+ const { vuePackage, reactPackage } = options;
88
+ if (vuePackage) {
89
+ options$ = mergeConfig(sharedVueConfig, options$);
90
+ }
91
+ if (reactPackage) {
92
+ options$ = mergeConfig(sharedReactConfig, options$);
93
+ }
92
94
  }
95
+ process.env.DEV_OPTIONS = encodeURIComponent(JSON.stringify({
96
+ ...options,
97
+ workspace,
98
+ entries,
99
+ html,
100
+ subpackagesMap
101
+ }));
93
102
  const server = await createServer(options$);
94
103
  const $server = await server.listen();
95
104
  const { local = [], network = [] } = $server.resolvedUrls || {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deot/dev-dever",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -21,11 +21,14 @@
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
- "@deot/dev-shared": "^2.4.0",
24
+ "@deot/dev-react": "^2.5.0",
25
+ "@deot/dev-shared": "^2.5.0",
26
+ "@deot/dev-vue": "^2.5.0",
25
27
  "ejs": "^3.1.9",
26
28
  "vite": "^4.4.9"
27
29
  },
28
30
  "devDependencies": {
31
+ "@deot/dev-test": "^2.5.0",
29
32
  "cross-env": "^7.0.3"
30
33
  }
31
34
  }
package/shared.config.ts CHANGED
@@ -4,46 +4,21 @@ import { createRequire } from "node:module";
4
4
  import { defineConfig } from 'vitest/config';
5
5
  import type { UserConfig, ViteDevServer } from 'vite';
6
6
 
7
+ /**
8
+ * https://github.com/vuejs/core/issues/8303
9
+ * to fix error: ReferenceError: __name is not defined
10
+ */
11
+ let __defProp = Object.defineProperty;
12
+ let __name = (target: any, value: any) => __defProp(target, 'name', { value, configurable: true });
13
+ globalThis.__name = globalThis.__name || __name;
14
+
7
15
  const cwd = process.cwd();
8
16
 
9
17
  // devOptions
10
18
  const devOptions = JSON.parse(decodeURIComponent(process.env.DEV_OPTIONS || '{}'));
11
- const { workspace, html } = devOptions;
12
-
13
- // alias
14
- const replacement = (name: string) => path.resolve(cwd, `./packages/${name}/src`);
15
- const { name } = createRequire(cwd)(path.resolve(cwd, workspace ? `${workspace}/index` : '', 'package.json'));
16
-
17
- const getHtmlContent = async (url: string) => {
18
- let fullpath = path.join(cwd, workspace, url);
19
-
20
- if (
21
- /^\/?@vite/.test(url)
22
- || (fs.existsSync(fullpath) && fs.statSync(fullpath).isFile())
23
- ) {
24
- return;
25
- }
26
-
27
- if (url === '/') return html;
28
-
29
- const info = url.split('/').filter(i => !!i);
30
-
31
- const prefix = info.slice(0, -1);
32
- const entry = info.slice(-1)[0];
33
-
34
- if (prefix[prefix.length - 1] !== 'examples') {
35
- prefix.push('examples');
36
- }
37
-
38
- fullpath = path.join(
39
- cwd,
40
- workspace,
41
- prefix.join('/'),
42
- `${entry?.replace(/(\.html)$/, '.ts')}`
43
- );
44
-
45
- if (!fs.existsSync(fullpath)) return /\.[\s\S]+$/.test(entry) ? undefined : html;
19
+ const { workspace, html, subpackagesMap } = devOptions;
46
20
 
21
+ const generateIndexHtml = (url: string, inject: string) => {
47
22
  let contents = '';
48
23
  contents += `<!DOCTYPE html>\n`;
49
24
  contents += `<html lang="en">\n`;
@@ -53,14 +28,81 @@ const getHtmlContent = async (url: string) => {
53
28
  contents += ` <title>demo-${url}</title>\n`;
54
29
  contents += ` </head>\n`;
55
30
  contents += ` <body>\n`;
31
+ contents += ` <div id="app"></div>\n`;
56
32
  contents += ` <script type="module">\n`;
57
- contents += ` import "/${path.relative(cwd, fullpath)}";\n`;
33
+ contents += inject;
34
+
58
35
  contents += ` </script>\n`;
59
36
  contents += ` </body>\n`;
60
37
  contents += `</html>\n`;
38
+
61
39
  return contents;
62
40
  };
63
41
 
42
+ const getVirtualHtml = async (url: string) => {
43
+ const info = url.split('/').filter(i => !!i);
44
+
45
+ const prefix = info.slice(0, -1);
46
+ const entry = info.slice(-1)[0];
47
+
48
+ if (prefix[prefix.length - 1] !== 'examples') {
49
+ prefix.push('examples');
50
+ }
51
+
52
+ if (workspace && prefix[0] !== workspace) {
53
+ prefix.unshift(workspace);
54
+ }
55
+
56
+ const dir = path.join(cwd, prefix.join('/'));
57
+ const isExist = (ext: string) => {
58
+ const fullpath = path.join(dir, `${entry.replace(/(.*)(\..*)$/, '$1') + ext}`);
59
+ return fs.existsSync(fullpath) ? fullpath : false;
60
+ };
61
+
62
+ const htmlFullpath = isExist('.html');
63
+ if (htmlFullpath) {
64
+ return fs.readFileSync(htmlFullpath).toString();
65
+ }
66
+
67
+ const tsFullpath = isExist('.ts');
68
+ if (tsFullpath) {
69
+ let inject = '';
70
+ inject += ` import "/${path.relative(cwd, tsFullpath)}";\n`;
71
+ return generateIndexHtml(url, inject);
72
+ }
73
+
74
+ const vueFullpath = isExist('.vue');
75
+ if (vueFullpath) {
76
+ let inject = '';
77
+ inject += ` import { createApp } from "vue"\n`;
78
+ inject += ` import App from "/${path.relative(cwd, vueFullpath)}";\n`;
79
+ inject += ` const app = createApp(App);\n`;
80
+ inject += ` app.mount("#app");\n`;
81
+ inject += ` typeof window !== "undefined" && (window.app = app);\n`;
82
+ return generateIndexHtml(url, inject);
83
+ }
84
+
85
+ const tsxFullpath = isExist('.tsx');
86
+ if (tsxFullpath) {
87
+ let inject = '';
88
+ inject += ` import React, { StrictMode } from 'react';`;
89
+ inject += ` import { createRoot } from 'react-dom/client';`;
90
+ inject += ` import App from "/${path.relative(cwd, tsxFullpath)}";\n`;
91
+ inject += ` const h = React.createElement\n`;
92
+ inject += ` const app = createRoot(document.getElementById('app'));\n`;
93
+ inject += ` app.render(h(StrictMode, {}, h(App)))\n`;
94
+
95
+ return generateIndexHtml(url, inject);
96
+ }
97
+ };
98
+
99
+
100
+ // alias
101
+ const require$ = createRequire(cwd);
102
+ const getPackageName = (name: string) => (require$(path.resolve(cwd, workspace ? `${workspace}/${name}` : '', 'package.json'))).name;
103
+ const replacement = (name: string, isSubpackage?: boolean) => path.resolve(cwd, `./packages/${name}`, isSubpackage ? 'index.ts' : './src');
104
+ const name = getPackageName('index');
105
+
64
106
  export default defineConfig({
65
107
  resolve: workspace
66
108
  ? {
@@ -69,6 +111,15 @@ export default defineConfig({
69
111
  find: new RegExp(`^${name}$`),
70
112
  replacement: replacement('index')
71
113
  },
114
+ ...Object.keys(subpackagesMap).reduce((pre, cur: string) => {
115
+ if (subpackagesMap[cur].length) {
116
+ pre.push({
117
+ find: new RegExp(`^${getPackageName(cur)}$`),
118
+ replacement: replacement(cur, true)
119
+ });
120
+ }
121
+ return pre;
122
+ }, [] as any),
72
123
  {
73
124
 
74
125
  find: new RegExp(`^${name}-(.*?)$`),
@@ -82,15 +133,35 @@ export default defineConfig({
82
133
  name: 'vite-plugin-virtual-html',
83
134
  configureServer(server: ViteDevServer) {
84
135
  server.middlewares.use(async (req, res, next) => {
85
- const url = req.url as string;
136
+ if (res.writableEnded) {
137
+ return next();
138
+ }
139
+ if (req.url!.includes('html-proxy&')) {
140
+ return next();
141
+ }
86
142
 
87
- const content = await getHtmlContent(url);
143
+ let url = req.url?.replace(/[?#].*$/s, '') || '';
144
+ if (url === '/') return res.end(html);
88
145
 
89
- if (!content) {
146
+ // 文件已存在,这样xxx.png可以被获取,真实路径的.ts,.html都可以被获取
147
+ if (fs.existsSync(path.join(cwd, url))) {
90
148
  return next();
91
149
  }
92
150
 
93
- res.end(content);
151
+ let vHtml = await getVirtualHtml(url);
152
+ if (
153
+ (url?.endsWith('.html') || vHtml)
154
+ && req.headers['sec-fetch-dest'] !== 'script'
155
+ ) {
156
+ if (!vHtml) {
157
+ return res.end(html);
158
+ }
159
+ vHtml = await server.transformIndexHtml(url, vHtml, req.originalUrl);
160
+ res.end(vHtml);
161
+ return;
162
+ }
163
+
164
+ next();
94
165
  });
95
166
  }
96
167
  }