nativescript-web-adapter 0.1.2 → 0.1.3

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.
Files changed (97) hide show
  1. package/README.md +218 -246
  2. package/core/components/AbsoluteLayout.vue +11 -0
  3. package/core/components/ActionBar.vue +11 -0
  4. package/core/components/ActionItem.vue +11 -0
  5. package/core/components/ActivityIndicator.vue +15 -0
  6. package/core/components/Button.vue +41 -0
  7. package/core/components/DatePicker.vue +27 -0
  8. package/core/components/DockLayout.vue +23 -0
  9. package/core/components/FlexboxLayout.vue +11 -0
  10. package/core/components/Frame.vue +11 -0
  11. package/core/components/GridLayout.vue +85 -0
  12. package/core/components/HtmlView.vue +13 -0
  13. package/core/components/Image.vue +12 -0
  14. package/core/components/ImageCacheIt.vue +12 -0
  15. package/core/components/Label.vue +15 -0
  16. package/core/components/ListPicker.vue +21 -0
  17. package/core/components/ListView.vue +12 -0
  18. package/core/components/NavigationButton.vue +28 -0
  19. package/core/components/Page.vue +18 -0
  20. package/core/components/Placeholder.vue +11 -0
  21. package/core/components/Progress.vue +12 -0
  22. package/core/components/RootLayout.vue +11 -0
  23. package/core/components/ScrollView.vue +11 -0
  24. package/core/components/SearchBar.vue +22 -0
  25. package/core/components/SegmentedBar.vue +50 -0
  26. package/core/components/SegmentedBarItem.vue +21 -0
  27. package/core/components/Slider.vue +18 -0
  28. package/core/components/StackLayout.vue +11 -0
  29. package/core/components/Switch.vue +26 -0
  30. package/core/components/TabView.vue +48 -0
  31. package/core/components/TabViewItem.vue +27 -0
  32. package/core/components/TextField.vue +15 -0
  33. package/core/components/TextView.vue +18 -0
  34. package/core/components/TimePicker.vue +21 -0
  35. package/core/components/WebView.vue +13 -0
  36. package/core/components/WrapLayout.vue +11 -0
  37. package/core/components/index.js +3 -0
  38. package/core/components/index.ts +35 -0
  39. package/core/composables/dialogs.ts +31 -0
  40. package/core/composables/index.js +3 -0
  41. package/core/composables/index.ts +4 -0
  42. package/core/composables/useActionBar.js +7 -0
  43. package/core/composables/useActionBar.ts +19 -0
  44. package/core/composables/useFrame.js +8 -0
  45. package/core/composables/useFrame.ts +25 -0
  46. package/core/composables/usePage.js +8 -0
  47. package/core/composables/usePage.ts +25 -0
  48. package/core/env.d.ts +7 -0
  49. package/core/index.js +4 -0
  50. package/core/index.ts +85 -0
  51. package/core/types.ts +12 -0
  52. package/dist/nativescript-web-adapter.es.js +83 -0
  53. package/dist/nativescript-web-adapter.umd.js +1 -0
  54. package/dist/style.css +1 -0
  55. package/package.json +35 -49
  56. package/tools/cli.cjs +45 -0
  57. package/tools/create-web-platform.cjs +76 -0
  58. package/tools/create-web-platform.js +196 -0
  59. package/tools/modules/appPatch.cjs +27 -0
  60. package/tools/modules/copy.cjs +84 -0
  61. package/tools/modules/router.cjs +46 -0
  62. package/tools/modules/templates.cjs +130 -0
  63. package/tools/modules/transform.cjs +93 -0
  64. package/dist/core.cjs +0 -3
  65. package/dist/core.cjs.map +0 -1
  66. package/dist/core.js +0 -2
  67. package/dist/core.js.map +0 -1
  68. package/dist/index.cjs +0 -377
  69. package/dist/index.cjs.map +0 -1
  70. package/dist/index.css +0 -172
  71. package/dist/index.js +0 -361
  72. package/dist/index.js.map +0 -1
  73. package/dist/types/core/index.d.ts +0 -8
  74. package/dist/types/index.d.ts +0 -1
  75. package/dist/types/index.types.d.ts +0 -1
  76. package/dist/types/vue/components/ActionBar.d.ts +0 -5
  77. package/dist/types/vue/components/ActionItem.d.ts +0 -15
  78. package/dist/types/vue/components/Button.d.ts +0 -26
  79. package/dist/types/vue/components/ContentView.d.ts +0 -3
  80. package/dist/types/vue/components/FlexboxLayout.d.ts +0 -35
  81. package/dist/types/vue/components/Frame.d.ts +0 -3
  82. package/dist/types/vue/components/GridLayout.d.ts +0 -26
  83. package/dist/types/vue/components/ImageCacheIt.d.ts +0 -23
  84. package/dist/types/vue/components/Label.d.ts +0 -26
  85. package/dist/types/vue/components/ListView.d.ts +0 -24
  86. package/dist/types/vue/components/Page.d.ts +0 -5
  87. package/dist/types/vue/components/StackLayout.d.ts +0 -5
  88. package/dist/types/vue/components/TabView.d.ts +0 -26
  89. package/dist/types/vue/components/TabViewItem.d.ts +0 -24
  90. package/dist/types/vue/index.d.ts +0 -18
  91. package/dist/types/vue/index.types.d.ts +0 -17
  92. package/dist/types/vue.d.ts +0 -266
  93. package/dist/vue.cjs +0 -377
  94. package/dist/vue.cjs.map +0 -1
  95. package/dist/vue.css +0 -172
  96. package/dist/vue.js +0 -361
  97. package/dist/vue.js.map +0 -1
@@ -0,0 +1,196 @@
1
+ // 文件扩展名应为 .cjs 以兼容 CommonJS require
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ // CommonJS export will be set at the end of the file
7
+ function createWebPlatform(options = {}) {
8
+ const cwd = process.cwd();
9
+ const platformsDir = path.join(cwd, 'platforms');
10
+ const webDir = path.join(platformsDir, 'web');
11
+ const srcDir = path.join(cwd, 'src');
12
+
13
+ // 确保platforms/web目录存在
14
+ if (!fs.existsSync(webDir)) {
15
+ fs.mkdirSync(webDir, { recursive: true });
16
+ }
17
+
18
+ // 复制源代码到web平台
19
+ copySourceFiles(srcDir, path.join(webDir, 'src'));
20
+ // 复制适配器的 composables 到 web 项目的 src/composables/websfc
21
+ try {
22
+ const adapterComposablesDir = path.join(__dirname, '..', 'core', 'composables');
23
+ const targetComposablesDir = path.join(webDir, 'src', 'composables', 'websfc');
24
+ copyAdapterDir(adapterComposablesDir, targetComposablesDir);
25
+ } catch (err) {
26
+ console.warn('[web-adapter] 复制适配器 composables 失败:', err);
27
+ }
28
+
29
+ // 创建web平台特定的文件
30
+ createWebPlatformFiles(webDir);
31
+
32
+ // 安装依赖
33
+ installDependencies(webDir);
34
+ }
35
+
36
+ function copyAdapterDir(srcDir, destDir) {
37
+ if (!fs.existsSync(srcDir)) {
38
+ // no composables to copy
39
+ return;
40
+ }
41
+ if (!fs.existsSync(destDir)) {
42
+ fs.mkdirSync(destDir, { recursive: true });
43
+ }
44
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
45
+ for (const entry of entries) {
46
+ const srcPath = path.join(srcDir, entry.name);
47
+ const destPath = path.join(destDir, entry.name);
48
+ if (entry.isDirectory()) {
49
+ copyAdapterDir(srcPath, destPath);
50
+ } else {
51
+ try {
52
+ fs.copyFileSync(srcPath, destPath);
53
+ } catch (err) {
54
+ console.error('[web-adapter] 复制文件失败:', srcPath, err);
55
+ }
56
+ }
57
+ }
58
+ }
59
+
60
+ function copySourceFiles(src, dest) {
61
+ if (!fs.existsSync(dest)) {
62
+ fs.mkdirSync(dest, { recursive: true });
63
+ }
64
+
65
+ const entries = fs.readdirSync(src, { withFileTypes: true });
66
+
67
+ for (const entry of entries) {
68
+ const srcPath = path.join(src, entry.name);
69
+ const destPath = path.join(dest, entry.name);
70
+
71
+ if (entry.isDirectory()) {
72
+ copySourceFiles(srcPath, destPath);
73
+ } else {
74
+ // 转换并复制文件
75
+ let content = fs.readFileSync(srcPath, 'utf8');
76
+ content = transformContent(content);
77
+ fs.writeFileSync(destPath, content);
78
+ }
79
+ }
80
+ }
81
+
82
+ function transformContent(content) {
83
+ // 将nativescript特定的导入替换为web版本
84
+ content = content.replace(/from\s+['"](nativescript-vue)['"]/g, "from 'vue'");
85
+ content = content.replace(/from\s+['"]([@]nativescript\/core)['"]/g, "from 'nativescript-web-adapter'");
86
+
87
+ // 移除registerElement调用
88
+ content = content.replace(/registerElement\([^)]+\);?\n?/g, '// registerElement removed for web\n');
89
+
90
+ // 移除平台特定代码
91
+ if (content.includes('__ANDROID__') || content.includes('Application.launchEvent')) {
92
+ content = content.replace(/Application\.on[\s\S]*?}\);/g, '');
93
+ }
94
+
95
+ return content;
96
+ }
97
+
98
+ function createWebPlatformFiles(webDir) {
99
+ // 创建index.html
100
+ const indexHtml = `<!DOCTYPE html>
101
+ <html lang="en">
102
+ <head>
103
+ <meta charset="UTF-8" />
104
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
105
+ <title>NS Vue Web</title>
106
+ </head>
107
+ <body>
108
+ <div id="app"></div>
109
+ <script type="module" src="/src/app.ts"></script>
110
+ </body>
111
+ </html>`;
112
+
113
+ fs.writeFileSync(path.join(webDir, 'index.html'), indexHtml);
114
+
115
+ // 创建web平台的package.json
116
+ const packageJson = {
117
+ name: "ns-vue-web-platform",
118
+ private: true,
119
+ scripts: {
120
+ dev: "vite",
121
+ build: "vite build"
122
+ },
123
+ dependencies: {
124
+ "vue": "^3.4.0",
125
+ "nativescript-web-adapter": "file:../../nativescript-web-adapter"
126
+ },
127
+ devDependencies: {
128
+ "@vitejs/plugin-vue": "^5.0.0",
129
+ "typescript": "^5.0.0",
130
+ "vite": "^5.0.0",
131
+ "autoprefixer": "^10.4.16",
132
+ "postcss": "^8.4.31",
133
+ "tailwindcss": "^3.4.0"
134
+ }
135
+ };
136
+
137
+ fs.writeFileSync(
138
+ path.join(webDir, 'package.json'),
139
+ JSON.stringify(packageJson, null, 2)
140
+ );
141
+
142
+ // 创建vite.config.ts(设置 dev server 端口为 3005,避免冲突)
143
+ const viteConfig = `import { defineConfig } from 'vite';
144
+ import vue from '@vitejs/plugin-vue';
145
+ import path from 'path';
146
+
147
+ export default defineConfig({
148
+ plugins: [vue()],
149
+ resolve: {
150
+ alias: {
151
+ '@': path.resolve(__dirname, './src'),
152
+ '@nativescript/core': 'nativescript-web-adapter'
153
+ }
154
+ },
155
+ server: {
156
+ port: 3005,
157
+ strictPort: true
158
+ }
159
+ });`;
160
+
161
+ fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig);
162
+
163
+ // 创建postcss.config.js
164
+ const postcssConfig = `module.exports = {
165
+ plugins: {
166
+ tailwindcss: {},
167
+ autoprefixer: {},
168
+ },
169
+ };`;
170
+
171
+ fs.writeFileSync(path.join(webDir, 'postcss.config.js'), postcssConfig);
172
+
173
+ // 创建tailwind.config.js
174
+ const tailwindConfig = `/** @type {import('tailwindcss').Config} */
175
+ module.exports = {
176
+ content: [
177
+ "./index.html",
178
+ "./src/**/*.{vue,js,ts,jsx,tsx}",
179
+ ],
180
+ theme: {
181
+ extend: {},
182
+ },
183
+ plugins: [],
184
+ };`;
185
+
186
+ fs.writeFileSync(path.join(webDir, 'tailwind.config.js'), tailwindConfig);
187
+ }
188
+
189
+ function installDependencies(webDir) {
190
+ const { execSync } = require('child_process');
191
+ execSync('npm install', { cwd: webDir, stdio: 'inherit' });
192
+ }
193
+
194
+ module.exports = {
195
+ createWebPlatform
196
+ };
@@ -0,0 +1,27 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function patchAppForWeb(webDir) {
5
+ try {
6
+ const appPath = path.join(webDir, 'src', 'app.ts');
7
+ if (!fs.existsSync(appPath)) {
8
+ console.warn('[web-adapter] 未找到 app.ts,跳过 app 修补');
9
+ return;
10
+ }
11
+
12
+ // 动态扫描 websfc 组件目录,生成 import 与注册语句
13
+ const websfcDir = path.join(webDir, 'src', 'components', 'websfc');
14
+ const entries = fs.existsSync(websfcDir) ? fs.readdirSync(websfcDir) : [];
15
+ const vueFiles = entries.filter(f => f.endsWith('.vue'));
16
+ const imports = vueFiles.map(f => `import ${path.basename(f, '.vue')} from './components/websfc/${f}';`).join('\n');
17
+ const registers = vueFiles.map(f => `app.component("${path.basename(f, '.vue')}", ${path.basename(f, '.vue')});`).join('\n');
18
+ const content = `${imports}\nimport * as ns from './composables/websfc/index.ts';\nimport { createApp } from 'vue';\nimport { initGlobals } from "./globals";\nimport router from './router';\nimport App from './App.vue';\nimport './app.css';\n\ninitGlobals();\n\nconst app = createApp(App);\n\n// Register web components\n${registers}\n\n// Register global composables for dialogs, frame, page, etc.\napp.config.globalProperties.$ns = ns;\n\napp.use(router);\napp.mount('#app');`;
19
+
20
+ fs.writeFileSync(appPath, content, 'utf8');
21
+ console.log('[web-adapter] 已修补 app.ts');
22
+ } catch (err) {
23
+ console.error('[web-adapter] 修补 app.ts 时出错:', err);
24
+ }
25
+ }
26
+
27
+ module.exports = { patchAppForWeb };
@@ -0,0 +1,84 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function copyAdapterComponents(srcDir, destDir) {
5
+ if (!fs.existsSync(srcDir)) {
6
+ console.warn('[web-adapter] 适配器组件目录不存在:', srcDir);
7
+ return;
8
+ }
9
+ if (!fs.existsSync(destDir)) {
10
+ fs.mkdirSync(destDir, { recursive: true });
11
+ }
12
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
13
+ for (const entry of entries) {
14
+ const srcPath = path.join(srcDir, entry.name);
15
+ const destPath = path.join(destDir, entry.name);
16
+ if (entry.isDirectory()) {
17
+ if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });
18
+ copyAdapterComponents(srcPath, destPath);
19
+ } else {
20
+ try {
21
+ fs.copyFileSync(srcPath, destPath);
22
+ } catch (err) {
23
+ console.error('[web-adapter] 复制组件失败:', srcPath, err);
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+ function copyAdapterComposables(srcDir, destDir) {
30
+ if (!fs.existsSync(srcDir)) {
31
+ console.warn('[web-adapter] 适配器 composables 目录不存在:', srcDir);
32
+ return;
33
+ }
34
+ if (!fs.existsSync(destDir)) {
35
+ fs.mkdirSync(destDir, { recursive: true });
36
+ }
37
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
38
+ for (const entry of entries) {
39
+ const srcPath = path.join(srcDir, entry.name);
40
+ const destPath = path.join(destDir, entry.name);
41
+ if (entry.isDirectory()) {
42
+ if (!fs.existsSync(destPath)) fs.mkdirSync(destPath, { recursive: true });
43
+ copyAdapterComposables(srcPath, destPath);
44
+ } else {
45
+ try {
46
+ fs.copyFileSync(srcPath, destPath);
47
+ } catch (err) {
48
+ console.error('[web-adapter] 复制 composable 文件失败:', srcPath, err);
49
+ }
50
+ }
51
+ }
52
+ }
53
+
54
+ function copySourceFiles(src, dest, transformContent) {
55
+ if (!fs.existsSync(src)) {
56
+ console.warn('[web-adapter] 源代码目录不存在:', src);
57
+ return;
58
+ }
59
+ if (!fs.existsSync(dest)) {
60
+ fs.mkdirSync(dest, { recursive: true });
61
+ }
62
+ const entries = fs.readdirSync(src, { withFileTypes: true });
63
+ for (const entry of entries) {
64
+ const srcPath = path.join(src, entry.name);
65
+ const destPath = path.join(dest, entry.name);
66
+ if (entry.isDirectory()) {
67
+ copySourceFiles(srcPath, destPath, transformContent);
68
+ } else {
69
+ try {
70
+ let content = fs.readFileSync(srcPath, 'utf8');
71
+ content = transformContent ? transformContent(content, srcPath) : content;
72
+ fs.writeFileSync(destPath, content);
73
+ } catch (err) {
74
+ console.error('[web-adapter] 复制文件失败:', srcPath, err);
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ module.exports = {
81
+ copyAdapterComponents,
82
+ copyAdapterComposables,
83
+ copySourceFiles,
84
+ };
@@ -0,0 +1,46 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function buildRouterFromPages(webDir) {
5
+ const pagesDir = path.join(webDir, 'src', 'pages');
6
+ const lines = [];
7
+ lines.push(`import { createRouter, createWebHistory } from 'vue-router'`);
8
+ let routes = [];
9
+ if (fs.existsSync(pagesDir)) {
10
+ const entries = fs.readdirSync(pagesDir, { withFileTypes: true });
11
+ for (const entry of entries) {
12
+ if (!entry.isFile()) continue;
13
+ if (!/\.vue$/i.test(entry.name)) continue;
14
+ const base = entry.name.replace(/\.vue$/i, '');
15
+ const importName = toIdentifier(base);
16
+ lines.push(`import ${importName} from '../pages/${entry.name}'`);
17
+ const routePath = base.toLowerCase() === 'index' ? '/' : `/${base}`;
18
+ routes.push(` { path: '${routePath}', name: '${base}', component: ${importName} }`);
19
+ }
20
+ }
21
+ if (routes.length === 0) {
22
+ lines.push(`import Home from '../components/Home.vue'`);
23
+ routes.push(` { path: '/', name: 'Home', component: Home }`);
24
+ }
25
+ lines.push('');
26
+ lines.push('const routes = [');
27
+ lines.push(routes.join(',\n'));
28
+ lines.push(']');
29
+ lines.push('');
30
+ lines.push('const router = createRouter({');
31
+ lines.push(' history: createWebHistory(),');
32
+ lines.push(' routes');
33
+ lines.push('})');
34
+ lines.push('');
35
+ lines.push('export default router');
36
+ return lines.join('\n');
37
+ }
38
+
39
+ function toIdentifier(name) {
40
+ let id = name.replace(/[^a-zA-Z0-9_$]/g, '_');
41
+ if (/^[0-9]/.test(id)) id = '_' + id;
42
+ id = id.replace(/(^|_)([a-z])/g, (m, p1, p2) => p1 + p2.toUpperCase());
43
+ return id;
44
+ }
45
+
46
+ module.exports = { buildRouterFromPages, toIdentifier };
@@ -0,0 +1,130 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function createWebPlatformFiles(webDir) {
5
+ const projectRoot = path.dirname(path.dirname(webDir));
6
+ // 创建或更新 package.json
7
+ fs.writeFileSync(path.join(webDir, 'package.json'), JSON.stringify({
8
+ "name": "web-platform",
9
+ "version": "1.0.0",
10
+ "private": true,
11
+ "scripts": {
12
+ "dev": "vite",
13
+ "build": "vue-tsc --noEmit && vite build",
14
+ "preview": "vite preview"
15
+ },
16
+ "dependencies": {
17
+ "vue": "^3.3.4",
18
+ "vue-router": "^4.2.5"
19
+ },
20
+ "devDependencies": {
21
+ "@vitejs/plugin-vue": "^4.2.3",
22
+ "typescript": "^5.0.2",
23
+ "vite": "^4.4.5",
24
+ "vue-tsc": "^1.8.5",
25
+ "autoprefixer": "^10.4.16",
26
+ "postcss": "^8.4.31",
27
+ "tailwindcss": "^3.4.0"
28
+ }
29
+ }, null, 2));
30
+
31
+ // index.html
32
+ fs.writeFileSync(path.join(webDir, 'index.html'), `<!DOCTYPE html>
33
+ <html lang="en">
34
+ <head>
35
+ <meta charset="UTF-8" />
36
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
37
+ <title>NS Vue Web</title>
38
+ </head>
39
+ <body>
40
+ <div id="app"></div>
41
+ <script type="module" src="/src/app.ts"></script>
42
+ </body>
43
+ </html>`);
44
+
45
+ // vite.config.ts
46
+ const packageJson = {
47
+ name: "ns-vue-web-platform",
48
+ private: true,
49
+ scripts: {
50
+ dev: "vite",
51
+ build: "vite build"
52
+ },
53
+ dependencies: {
54
+ "vue": "^3.4.0",
55
+ "vue-router": "^4.2.5"
56
+ },
57
+ devDependencies: {
58
+ "@vitejs/plugin-vue": "^5.0.0",
59
+ "typescript": "^5.0.0",
60
+ "vite": "^5.0.0",
61
+ "autoprefixer": "^10.4.16",
62
+ "postcss": "^8.4.31",
63
+ "tailwindcss": "^3.4.0"
64
+ }
65
+ };
66
+ fs.writeFileSync(
67
+ path.join(webDir, 'package.json'),
68
+ JSON.stringify(packageJson, null, 2)
69
+ );
70
+ const viteConfig = `import { defineConfig } from 'vite';
71
+ import vue from '@vitejs/plugin-vue';
72
+ import path from 'path';
73
+
74
+ export default defineConfig({
75
+ plugins: [vue()],
76
+ resolve: {
77
+ alias: {
78
+ '@': path.resolve(__dirname, './src')
79
+ }
80
+ },
81
+ server: {
82
+ port: 3005,
83
+ strictPort: false
84
+ }
85
+ });`;
86
+ fs.writeFileSync(path.join(webDir, 'vite.config.ts'), viteConfig);
87
+
88
+ // postcss & tailwind configs: 复用根配置(如果存在),否则写默认
89
+ const rootPostcss = path.join(projectRoot, 'postcss.config.js');
90
+ const rootTailwind = path.join(projectRoot, 'tailwind.config.js');
91
+ try {
92
+ if (fs.existsSync(rootPostcss)) {
93
+ fs.copyFileSync(rootPostcss, path.join(webDir, 'postcss.config.js'));
94
+ } else {
95
+ const postcssConfig = `module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};`;
96
+ fs.writeFileSync(path.join(webDir, 'postcss.config.js'), postcssConfig);
97
+ }
98
+ } catch (e) {
99
+ console.warn('[web-adapter] 复制 postcss 配置失败,使用默认:', e?.message);
100
+ const postcssConfig = `module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};`;
101
+ fs.writeFileSync(path.join(webDir, 'postcss.config.js'), postcssConfig);
102
+ }
103
+ try {
104
+ if (fs.existsSync(rootTailwind)) {
105
+ fs.copyFileSync(rootTailwind, path.join(webDir, 'tailwind.config.js'));
106
+ } else {
107
+ const tailwindConfig = `/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n content: [\n "./index.html",\n "./src/**/*.{vue,js,ts,jsx,tsx}",\n ],\n theme: {\n extend: {},\n },\n plugins: [],\n};`;
108
+ fs.writeFileSync(path.join(webDir, 'tailwind.config.js'), tailwindConfig);
109
+ }
110
+ } catch (e) {
111
+ console.warn('[web-adapter] 复制 tailwind 配置失败,使用默认:', e?.message);
112
+ const tailwindConfig = `/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n content: [\n "./index.html",\n "./src/**/*.{vue,js,ts,jsx,tsx}",\n ],\n theme: {\n extend: {},\n },\n plugins: [],\n};`;
113
+ fs.writeFileSync(path.join(webDir, 'tailwind.config.js'), tailwindConfig);
114
+ }
115
+
116
+ // App.vue(根组件占位,仅渲染 <router-view/>)
117
+ const appVueContent = `<template>
118
+ <router-view></router-view>
119
+ </template>
120
+
121
+ <script setup lang="ts">
122
+ // App root component
123
+ </script>`;
124
+ const appVuePath = path.join(webDir, 'src', 'App.vue');
125
+ const srcDir = path.join(webDir, 'src');
126
+ if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir, { recursive: true });
127
+ fs.writeFileSync(appVuePath, appVueContent, 'utf8');
128
+ }
129
+
130
+ module.exports = { createWebPlatformFiles };
@@ -0,0 +1,93 @@
1
+ // Transform module: handle script-level transformations only
2
+ // - Replace 'nativescript-vue' imports with 'vue'
3
+ // - Remove '@nativescript/core' and adapter imports
4
+ // - Clean platform-specific globals and handlers
5
+ // - Keep template tags intact for custom web components to handle
6
+
7
+ function transformContent(content, srcPath) {
8
+ // globals.ts shim for web
9
+ if (srcPath && /globals\.ts$/.test(srcPath)) {
10
+ return "export function initGlobals() { /* web shim: no-op */ }\n";
11
+ }
12
+
13
+ // Import replacements
14
+ content = content.replace(/from\s+['\"](nativescript-vue)['\"]/g, "from 'vue'");
15
+ content = content.replace(/import\s+.*@nativescript\/core.*;?\n?/g, '');
16
+ content = content.replace(/import\s+.*nativescript-web-adapter.*;?\n?/g, '');
17
+
18
+ // Platform/global cleanup
19
+ content = content.replace(/declare\s+var\s+com[:\s\w]*;?\n?/g, '');
20
+
21
+ // Demo-specific native function replacement
22
+ content = content.replace(/function\s+enterNow\([^\)]*\)\s*\{[\s\S]*?\}\n?/g, "function enterNow() { window.open(\"https://viteconf.amsterdam\", '_blank'); }\n");
23
+ content = content.replace(/function\s+enterNow\([^\)]*\)\s*\{[\s\S]*?\}\s*[\s\S]*?let interval/g, 'function enterNow() { window.open("https://viteconf.amsterdam", \'_blank\'); }\n\nlet interval');
24
+
25
+ // Navigation: compile-time transform for web
26
+ // $navigateTo(Test) -> router.push('/Test')
27
+ // $navigateBack() -> router.go(-1)
28
+ // Frame.navigate(...) -> router.push('/...')
29
+ // Frame.goBack() -> router.go(-1)
30
+ if (srcPath && /\.vue$/i.test(srcPath)) {
31
+ const hasNavigateTo = /\$navigateTo\(\s*[A-Za-z_][A-Za-z0-9_]*\s*\)/.test(content);
32
+ const hasNavigateBack = /\$navigateBack\(\s*\)/.test(content);
33
+ const hasFrameNav = /Frame\.(navigate|goBack)\(/.test(content);
34
+ const hasFrameTopmost = /Frame\.topmost\(\)\.(navigate|goBack)\(/.test(content);
35
+ if (hasNavigateTo || hasNavigateBack || hasFrameNav || hasFrameTopmost) {
36
+ // Replace any property chain ending with $navigateTo(Symbol) -> router.push('/Symbol')
37
+ content = content.replace(/(?:this\.|[A-Za-z_$]+\?\.|[A-Za-z_$]+\.)*\$navigateTo\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/g, "router.push('/$1')");
38
+ // Replace any property chain ending with $navigateBack() -> router.go(-1)
39
+ content = content.replace(/(?:this\.|[A-Za-z_$]+\?\.|[A-Za-z_$]+\.)*\$navigateBack\(\s*\)/g, 'router.go(-1)');
40
+ // Replace Frame.goBack() -> router.go(-1)
41
+ content = content.replace(/Frame\.goBack\(\s*\)/g, 'router.go(-1)');
42
+ // Replace Frame.navigate(Identifier) -> router.push('/Identifier')
43
+ content = content.replace(/Frame\.navigate\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/g, "router.push('/$1')");
44
+ // Replace Frame.navigate('pages/Test') or module path -> router.push('/Test')
45
+ content = content.replace(/Frame\.navigate\(\s*['\"]([^'\"]+)['\"]\s*\)/g, (m, p1) => {
46
+ const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
47
+ return `router.push('/${base}')`;
48
+ });
49
+ // Replace Frame.navigate({ moduleName: 'pages/Test' }) -> router.push('/Test')
50
+ content = content.replace(/Frame\.navigate\(\s*\{[\s\S]*?moduleName\s*:\s*['\"]([^'\"]+)['\"][\s\S]*?\}\s*\)/g, (m, p1) => {
51
+ const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
52
+ return `router.push('/${base}')`;
53
+ });
54
+ // Replace Frame.topmost().goBack() -> router.go(-1)
55
+ content = content.replace(/Frame\.topmost\(\)\.goBack\(\s*\)/g, 'router.go(-1)');
56
+ // Replace Frame.topmost().navigate(Identifier) -> router.push('/Identifier')
57
+ content = content.replace(/Frame\.topmost\(\)\.navigate\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/g, "router.push('/$1')");
58
+ // Replace Frame.topmost().navigate('pages/Test') -> router.push('/Test')
59
+ content = content.replace(/Frame\.topmost\(\)\.navigate\(\s*['\"]([^'\"]+)['\"]\s*\)/g, (m, p1) => {
60
+ const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
61
+ return `router.push('/${base}')`;
62
+ });
63
+ // Replace Frame.topmost().navigate({ moduleName: 'pages/Test' }) -> router.push('/Test')
64
+ content = content.replace(/Frame\.topmost\(\)\.navigate\(\s*\{[\s\S]*?moduleName\s*:\s*['\"]([^'\"]+)['\"][\s\S]*?\}\s*\)/g, (m, p1) => {
65
+ const base = String(p1).split('/')?.pop()?.replace(/\.vue$/i, '') || p1;
66
+ return `router.push('/${base}')`;
67
+ });
68
+ // Ensure router import inside <script> block
69
+ if (!/import\s+router\s+from\s+['\"]@\/router['\"]/.test(content)) {
70
+ content = content.replace(/(<script[^>]*>)/i, "$1\nimport router from '@/router';\n");
71
+ }
72
+ }
73
+ }
74
+
75
+ // Remove platform residual lines and blocks
76
+ content = content.replace(/.*(nativeApp|android\.|UIApplication|NSURL|NSDictionary|com\.tns|intent|startActivity|android\.content).*/g, '');
77
+ content = content.replace(/else\s*\{[\s\S]*?\}/g, '');
78
+
79
+ // Fix markup formatting artifacts
80
+ content = content.replace(/\/\s+\/>/g, '\/>');
81
+
82
+ // Remove registerElement
83
+ content = content.replace(/registerElement\([^)]+\);?\n?/g, '// registerElement removed for web\n');
84
+
85
+ // Remove Application.on handlers if present
86
+ if (content.includes('__ANDROID__') || content.includes('Application.launchEvent')) {
87
+ content = content.replace(/Application\.on[\s\S]*?}\);/g, '');
88
+ }
89
+
90
+ return content;
91
+ }
92
+
93
+ module.exports = { transformContent };
package/dist/core.cjs DELETED
@@ -1,3 +0,0 @@
1
- 'use strict';
2
-
3
- //# sourceMappingURL=core.cjs.map
package/dist/core.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
package/dist/core.js DELETED
@@ -1,2 +0,0 @@
1
-
2
- //# sourceMappingURL=core.js.map
package/dist/core.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}