nativescript-web-adapter 0.1.1 → 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 (88) hide show
  1. package/README.md +220 -168
  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 +34 -46
  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 -240
  69. package/dist/index.cjs.map +0 -1
  70. package/dist/index.js +0 -229
  71. package/dist/index.js.map +0 -1
  72. package/dist/types/core/index.d.ts +0 -8
  73. package/dist/types/index.d.ts +0 -1
  74. package/dist/types/vue/components/ActionBar.d.ts +0 -5
  75. package/dist/types/vue/components/Button.d.ts +0 -26
  76. package/dist/types/vue/components/FlexboxLayout.d.ts +0 -35
  77. package/dist/types/vue/components/Frame.d.ts +0 -3
  78. package/dist/types/vue/components/GridLayout.d.ts +0 -27
  79. package/dist/types/vue/components/ImageCacheIt.d.ts +0 -23
  80. package/dist/types/vue/components/Label.d.ts +0 -26
  81. package/dist/types/vue/components/Page.d.ts +0 -5
  82. package/dist/types/vue/components/StackLayout.d.ts +0 -5
  83. package/dist/types/vue/index.d.ts +0 -12
  84. package/dist/types/vue.d.ts +0 -169
  85. package/dist/vue.cjs +0 -240
  86. package/dist/vue.cjs.map +0 -1
  87. package/dist/vue.js +0 -229
  88. package/dist/vue.js.map +0 -1
@@ -0,0 +1,25 @@
1
+ import { Ref, ref } from 'vue';
2
+
3
+ export interface FrameState {
4
+ stack: Ref<any[]>;
5
+ push: (page: any) => void;
6
+ pop: () => any;
7
+ }
8
+
9
+ export function useFrame(): FrameState {
10
+ const stack = ref<any[]>([]);
11
+
12
+ function push(page: any) {
13
+ stack.value.push(page);
14
+ }
15
+
16
+ function pop() {
17
+ return stack.value.pop();
18
+ }
19
+
20
+ return {
21
+ stack,
22
+ push,
23
+ pop
24
+ };
25
+ }
@@ -0,0 +1,8 @@
1
+ import { ref } from 'vue';
2
+
3
+ export function usePage() {
4
+ const isVisible = ref(true);
5
+ function show() { isVisible.value = true; }
6
+ function hide() { isVisible.value = false; }
7
+ return { isVisible, show, hide };
8
+ }
@@ -0,0 +1,25 @@
1
+ import { Ref, ref } from 'vue';
2
+
3
+ export interface PageState {
4
+ isVisible: Ref<boolean>;
5
+ show: () => void;
6
+ hide: () => void;
7
+ }
8
+
9
+ export function usePage(): PageState {
10
+ const isVisible = ref(true);
11
+
12
+ function show() {
13
+ isVisible.value = true;
14
+ }
15
+
16
+ function hide() {
17
+ isVisible.value = false;
18
+ }
19
+
20
+ return {
21
+ isVisible,
22
+ show,
23
+ hide
24
+ };
25
+ }
package/core/env.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import type { DefineComponent } from 'vue';
5
+ const component: DefineComponent<{}, {}, any>;
6
+ export default component;
7
+ }
package/core/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import * as components from './components/index.js';
2
+ import * as composables from './composables/index.js';
3
+
4
+ export { components, composables };
package/core/index.ts ADDED
@@ -0,0 +1,85 @@
1
+ // Explicitly collect components and composables into objects so consumers
2
+ // can reference `core.components` and `core.composables` at runtime.
3
+ import ActionBar from './components/ActionBar.vue';
4
+ import Page from './components/Page.vue';
5
+ import Frame from './components/Frame.vue';
6
+ import StackLayout from './components/StackLayout.vue';
7
+ import GridLayout from './components/GridLayout.vue';
8
+ import FlexboxLayout from './components/FlexboxLayout.vue';
9
+ import WrapLayout from './components/WrapLayout.vue';
10
+ import ScrollView from './components/ScrollView.vue';
11
+ import Label from './components/Label.vue';
12
+ import Button from './components/Button.vue';
13
+ import Image from './components/Image.vue';
14
+ import HtmlView from './components/HtmlView.vue';
15
+ import ImageCacheIt from './components/ImageCacheIt.vue';
16
+ import TabView from './components/TabView.vue';
17
+ import TabViewItem from './components/TabViewItem.vue';
18
+ import RootLayout from './components/RootLayout.vue';
19
+ import DockLayout from './components/DockLayout.vue';
20
+ import AbsoluteLayout from './components/AbsoluteLayout.vue';
21
+ import ActionItem from './components/ActionItem.vue';
22
+ import NavigationButton from './components/NavigationButton.vue';
23
+ import ActivityIndicator from './components/ActivityIndicator.vue';
24
+ import DatePicker from './components/DatePicker.vue';
25
+ import TimePicker from './components/TimePicker.vue';
26
+ import ListPicker from './components/ListPicker.vue';
27
+ import ListView from './components/ListView.vue';
28
+ import Placeholder from './components/Placeholder.vue';
29
+ import Progress from './components/Progress.vue';
30
+ import SearchBar from './components/SearchBar.vue';
31
+ import SegmentedBar from './components/SegmentedBar.vue';
32
+ import SegmentedBarItem from './components/SegmentedBarItem.vue';
33
+ import Slider from './components/Slider.vue';
34
+ import SwitchComp from './components/Switch.vue';
35
+ import TextField from './components/TextField.vue';
36
+ import TextView from './components/TextView.vue';
37
+ import WebView from './components/WebView.vue';
38
+
39
+ export const components = {
40
+ ActionBar,
41
+ Page,
42
+ Frame,
43
+ StackLayout,
44
+ GridLayout,
45
+ FlexboxLayout,
46
+ WrapLayout,
47
+ ScrollView,
48
+ Label,
49
+ Button,
50
+ Image,
51
+ HtmlView,
52
+ ImageCacheIt,
53
+ TabView,
54
+ TabViewItem,
55
+ RootLayout,
56
+ DockLayout,
57
+ AbsoluteLayout,
58
+ ActionItem,
59
+ NavigationButton,
60
+ ActivityIndicator,
61
+ DatePicker,
62
+ TimePicker,
63
+ ListPicker,
64
+ ListView,
65
+ Placeholder,
66
+ Progress,
67
+ SearchBar,
68
+ SegmentedBar,
69
+ SegmentedBarItem,
70
+ Slider,
71
+ Switch: SwitchComp,
72
+ TextField,
73
+ TextView,
74
+ WebView,
75
+ };
76
+
77
+ import * as composablesNS from './composables';
78
+ export const composables = composablesNS;
79
+
80
+ // Re-export types for convenience
81
+ export * from './types';
82
+
83
+ // Also provide the original named exports for compatibility
84
+ export { ActionBar, Page, Frame, StackLayout, GridLayout, FlexboxLayout, WrapLayout, ScrollView, Label, Button, Image, HtmlView, ImageCacheIt, TabView, TabViewItem };
85
+ export { RootLayout, DockLayout, AbsoluteLayout, ActionItem, NavigationButton, ActivityIndicator, DatePicker, TimePicker, ListPicker, ListView, Placeholder, Progress, SearchBar, SegmentedBar, SegmentedBarItem, Slider, SwitchComp as Switch, TextField, TextView, WebView };
package/core/types.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { DefineComponent } from 'vue';
2
+ import type { FrameState } from './composables/useFrame';
3
+ import type { PageState } from './composables/usePage';
4
+ import type { ActionBarState } from './composables/useActionBar';
5
+
6
+ // 重新导出Vue组件类型
7
+ export type ActionBarComponent = DefineComponent;
8
+ export type PageComponent = DefineComponent;
9
+ export type FrameComponent = DefineComponent;
10
+
11
+ // 重新导出composables类型
12
+ export type { FrameState, PageState, ActionBarState };
@@ -0,0 +1,83 @@
1
+ import { defineComponent as r, createElementBlock as s, openBlock as c, renderSlot as a, ref as u } from "vue";
2
+ const f = { class: "ns-actionbar" }, p = /* @__PURE__ */ r({
3
+ name: "ActionBar",
4
+ __name: "ActionBar",
5
+ setup(e) {
6
+ return (t, o) => (c(), s("header", f, [
7
+ a(t.$slots, "default", {}, void 0, !0)
8
+ ]));
9
+ }
10
+ }), _ = (e, t) => {
11
+ const o = e.__vccOpts || e;
12
+ for (const [n, d] of t)
13
+ o[n] = d;
14
+ return o;
15
+ }, m = /* @__PURE__ */ _(p, [["__scopeId", "data-v-f29dfd84"]]), v = { class: "ns-page" }, b = /* @__PURE__ */ r({
16
+ name: "Page",
17
+ __name: "Page",
18
+ setup(e) {
19
+ return (t, o) => (c(), s("div", v, [
20
+ a(t.$slots, "default", {}, void 0, !0)
21
+ ]));
22
+ }
23
+ }), g = /* @__PURE__ */ _(b, [["__scopeId", "data-v-87719fa5"]]), h = { class: "ns-frame" }, $ = /* @__PURE__ */ r({
24
+ name: "Frame",
25
+ __name: "Frame",
26
+ setup(e) {
27
+ return (t, o) => (c(), s("div", h, [
28
+ a(t.$slots, "default", {}, void 0, !0)
29
+ ]));
30
+ }
31
+ }), O = /* @__PURE__ */ _($, [["__scopeId", "data-v-a66356e7"]]), i = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
32
+ __proto__: null,
33
+ ActionBar: m,
34
+ Frame: O,
35
+ Page: g
36
+ }, Symbol.toStringTag, { value: "Module" }));
37
+ function P() {
38
+ const e = u("");
39
+ function t(o) {
40
+ e.value = o;
41
+ }
42
+ return { title: e, setTitle: t };
43
+ }
44
+ function j() {
45
+ const e = u(!0);
46
+ function t() {
47
+ e.value = !0;
48
+ }
49
+ function o() {
50
+ e.value = !1;
51
+ }
52
+ return { isVisible: e, show: t, hide: o };
53
+ }
54
+ function y() {
55
+ const e = u([]);
56
+ function t(n) {
57
+ e.value.push(n);
58
+ }
59
+ function o() {
60
+ return e.value.pop();
61
+ }
62
+ return { stack: e, push: t, pop: o };
63
+ }
64
+ const l = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
65
+ __proto__: null,
66
+ useActionBar: P,
67
+ useFrame: y,
68
+ usePage: j
69
+ }, Symbol.toStringTag, { value: "Module" })), x = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
70
+ __proto__: null,
71
+ components: i,
72
+ composables: l
73
+ }, Symbol.toStringTag, { value: "Module" })), B = {
74
+ install(e) {
75
+ Object.entries(i || {}).forEach(([t, o]) => {
76
+ e.component(t, o);
77
+ }), e.config.globalProperties.$ns = l || {};
78
+ }
79
+ };
80
+ export {
81
+ x as core,
82
+ B as default
83
+ };
@@ -0,0 +1 @@
1
+ (function(r,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(r=typeof globalThis<"u"?globalThis:r||self,e(r.NativeScriptWebAdapter={},r.Vue))})(this,function(r,e){"use strict";const l={class:"ns-actionbar"},_=e.defineComponent({name:"ActionBar",__name:"ActionBar",setup(t){return(n,o)=>(e.openBlock(),e.createElementBlock("header",l,[e.renderSlot(n.$slots,"default",{},void 0,!0)]))}}),c=(t,n)=>{const o=t.__vccOpts||t;for(const[s,$]of n)o[s]=$;return o},u=c(_,[["__scopeId","data-v-f29dfd84"]]),d={class:"ns-page"},f=c(e.defineComponent({name:"Page",__name:"Page",setup(t){return(n,o)=>(e.openBlock(),e.createElementBlock("div",d,[e.renderSlot(n.$slots,"default",{},void 0,!0)]))}}),[["__scopeId","data-v-87719fa5"]]),p={class:"ns-frame"},a=Object.freeze(Object.defineProperty({__proto__:null,ActionBar:u,Frame:c(e.defineComponent({name:"Frame",__name:"Frame",setup(t){return(n,o)=>(e.openBlock(),e.createElementBlock("div",p,[e.renderSlot(n.$slots,"default",{},void 0,!0)]))}}),[["__scopeId","data-v-a66356e7"]]),Page:f},Symbol.toStringTag,{value:"Module"}));function m(){const t=e.ref("");function n(o){t.value=o}return{title:t,setTitle:n}}function b(){const t=e.ref(!0);function n(){t.value=!0}function o(){t.value=!1}return{isVisible:t,show:n,hide:o}}function g(){const t=e.ref([]);function n(s){t.value.push(s)}function o(){return t.value.pop()}return{stack:t,push:n,pop:o}}const i=Object.freeze(Object.defineProperty({__proto__:null,useActionBar:m,useFrame:g,usePage:b},Symbol.toStringTag,{value:"Module"})),h=Object.freeze(Object.defineProperty({__proto__:null,components:a,composables:i},Symbol.toStringTag,{value:"Module"})),S={install(t){Object.entries(a||{}).forEach(([n,o])=>{t.component(n,o)}),t.config.globalProperties.$ns=i||{}}};r.core=h,r.default=S,Object.defineProperties(r,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .ns-actionbar[data-v-f29dfd84]{background:#1f1140;color:#fff;padding:12px}.ns-page[data-v-87719fa5]{top:0;left:0;position:absolute;width:100%;min-height:100%;padding:0}
package/package.json CHANGED
@@ -1,59 +1,47 @@
1
1
  {
2
2
  "name": "nativescript-web-adapter",
3
- "version": "0.1.1",
4
- "repository": {
5
- "type": "git",
6
- "url": "https://github.com/ponzS/NativeScript-for-web.git"
7
- },
8
- "bugs": {
9
- "url": "https://github.com/ponzS/NativeScript-for-web/issues"
10
- },
11
- "homepage": "https://github.com/ponzS/NativeScript-for-web#readme",
12
- "files": [
13
- "dist",
14
- "README.md"
15
- ],
16
- "description": "Web adapter for NativeScript UI components (Vue 3)",
17
- "license": "MIT",
3
+ "version": "0.1.3",
4
+ "description": "Web adapter for NativeScript applications",
18
5
  "type": "module",
19
- "main": "dist/index.cjs",
20
- "module": "dist/index.js",
21
- "types": "dist/types/index.d.ts",
6
+ "main": "./dist/nativescript-web-adapter.umd.js",
7
+ "module": "./dist/nativescript-web-adapter.es.js",
8
+ "types": "./dist/index.d.ts",
22
9
  "exports": {
23
10
  ".": {
24
- "import": "./dist/index.js",
25
- "require": "./dist/index.cjs",
26
- "types": "./dist/types/index.d.ts"
27
- },
28
- "./vue": {
29
- "import": "./dist/vue.js",
30
- "require": "./dist/vue.cjs",
31
- "types": "./dist/types/vue.d.ts"
32
- },
33
- "./core": {
34
- "import": "./dist/core.js",
35
- "require": "./dist/core.cjs",
36
- "types": "./dist/types/core/index.d.ts"
11
+ "import": "./dist/nativescript-web-adapter.es.js",
12
+ "require": "./dist/nativescript-web-adapter.umd.js",
13
+ "types": "./dist/index.d.ts"
37
14
  }
38
15
  },
39
16
  "scripts": {
40
- "build": "rimraf dist && rollup -c",
41
- "types": "tsc -p tsconfig.json",
42
- "test": "vitest run",
43
- "dev": "vitest",
44
- "prepare": "npm run build && npm run types",
45
- "prepublishOnly": "npm run build && npm run types"
17
+ "create:web": "node tools/create-web-platform.cjs",
18
+ "dev": "vite",
19
+ "build": "vite build",
20
+ "preview": "vite preview",
21
+ "type-check": "vue-tsc --noEmit",
22
+ "prepublishOnly": "npm run build"
46
23
  },
47
- "peerDependencies": {
48
- "vue": "^3.4.0"
24
+ "bin": {
25
+ "ns-web": "./tools/cli.cjs"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "tools",
30
+ "templates",
31
+ "core"
32
+ ],
33
+ "dependencies": {
34
+ "vue": "^3.4.0",
35
+ "commander": "^11.0.0"
49
36
  },
50
37
  "devDependencies": {
51
- "@rollup/plugin-typescript": "^11.1.6",
52
- "rimraf": "^6.0.1",
53
- "rollup": "^4.22.0",
54
- "rollup-plugin-dts": "^6.0.2",
55
- "tslib": "^2.6.3",
56
- "typescript": "~5.9.0",
57
- "vitest": "^2.0.5"
38
+ "@types/node": "^20.0.0",
39
+ "typescript": "^5.0.0",
40
+ "@vitejs/plugin-vue": "^5.0.0",
41
+ "vite": "^5.0.0",
42
+ "vue-tsc": "^1.8.0"
43
+ },
44
+ "peerDependencies": {
45
+ "vue": "^3.0.0"
58
46
  }
59
47
  }
package/tools/cli.cjs ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ const { program } = require('commander');
3
+ const { createWebPlatform } = require('./create-web-platform.cjs');
4
+ const path = require('path');
5
+ const { execSync } = require('child_process');
6
+
7
+ program
8
+ .name('ns-web')
9
+ .description('CLI工具用于创建和管理NativeScript应用的web平台')
10
+ .version('1.0.0');
11
+
12
+ program
13
+ .command('init')
14
+ .description('为NativeScript项目初始化web平台支持')
15
+ .action(async () => {
16
+ await createWebPlatform();
17
+ });
18
+
19
+ program
20
+ .command('build')
21
+ .description('生成web平台并在 platforms/web 内构建')
22
+ .option('--skip-install', '跳过依赖安装')
23
+ .action(async (opts) => {
24
+ await createWebPlatform();
25
+ const webDir = path.join(process.cwd(), 'platforms', 'web');
26
+ if (!opts.skipInstall) {
27
+ execSync('npm install', { stdio: 'inherit', cwd: webDir });
28
+ }
29
+ execSync('npm run build', { stdio: 'inherit', cwd: webDir });
30
+ });
31
+
32
+ program
33
+ .command('dev')
34
+ .description('生成web平台并在 platforms/web 内启动开发服务器')
35
+ .option('--skip-install', '跳过依赖安装')
36
+ .action(async (opts) => {
37
+ await createWebPlatform();
38
+ const webDir = path.join(process.cwd(), 'platforms', 'web');
39
+ if (!opts.skipInstall) {
40
+ execSync('npm install', { stdio: 'inherit', cwd: webDir });
41
+ }
42
+ execSync('npm run dev', { stdio: 'inherit', cwd: webDir });
43
+ });
44
+
45
+ program.parse();
@@ -0,0 +1,76 @@
1
+ console.log('[web-adapter] create-web-platform.cjs 脚本已启动');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // 模块入口(全部实现下沉到 modules/*)
6
+ const copy = require('./modules/copy.cjs');
7
+ const transform = require('./modules/transform.cjs');
8
+ const routerGen = require('./modules/router.cjs');
9
+ const appPatch = require('./modules/appPatch.cjs');
10
+ const templates = require('./modules/templates.cjs');
11
+
12
+ function createWebPlatform(options = {}) {
13
+ const adapterDir = path.resolve(__dirname, '..');
14
+ // 当作为 node_modules 使用时,项目根应为当前工作目录
15
+ const projectRoot = options.projectRoot ? path.resolve(options.projectRoot) : process.cwd();
16
+ const platformsDir = path.join(projectRoot, 'platforms');
17
+ const webDir = path.join(platformsDir, 'web');
18
+ const srcDir = path.join(projectRoot, 'src');
19
+
20
+ console.log('[web-adapter] 项目根目录:', projectRoot);
21
+ console.log('[web-adapter] platforms 目录:', platformsDir);
22
+ console.log('[web-adapter] web 目录:', webDir);
23
+ console.log('[web-adapter] src 目录:', srcDir);
24
+
25
+ try {
26
+ if (!fs.existsSync(webDir)) {
27
+ fs.mkdirSync(webDir, { recursive: true });
28
+ console.log('[web-adapter] 已创建 web 目录');
29
+ } else {
30
+ console.log('[web-adapter] web 目录已存在');
31
+ }
32
+
33
+ // 1) 复制源码(仅脚本层转换,保留模板标签)
34
+ copy.copySourceFiles(srcDir, path.join(webDir, 'src'), transform.transformContent);
35
+ console.log('[web-adapter] 已复制 src 源代码');
36
+
37
+ // 2) 复制适配器 web 组件与 composables
38
+ const adapterComponentsDir = path.join(adapterDir, 'core', 'components');
39
+ const targetComponentsDir = path.join(webDir, 'src', 'components', 'websfc');
40
+ copy.copyAdapterComponents(adapterComponentsDir, targetComponentsDir);
41
+ console.log('[web-adapter] 已复制适配器组件到 websfc');
42
+
43
+ const adapterComposablesDir = path.join(adapterDir, 'core', 'composables');
44
+ const targetComposablesDir = path.join(webDir, 'src', 'composables', 'websfc');
45
+ copy.copyAdapterComposables(adapterComposablesDir, targetComposablesDir);
46
+ console.log('[web-adapter] 已复制适配器 composables 到 websfc');
47
+
48
+ // 3) 写入 web 项目模板(index.html、package.json、vite.config、postcss、tailwind、App.vue)
49
+ templates.createWebPlatformFiles(webDir);
50
+ console.log('[web-adapter] 已生成 web 平台模板与配置');
51
+
52
+ // 4) 生成路由(根据 pages 目录)
53
+ const routerDirPath = path.join(webDir, 'src', 'router');
54
+ if (!fs.existsSync(routerDirPath)) {
55
+ fs.mkdirSync(routerDirPath, { recursive: true });
56
+ }
57
+ const routerContent = routerGen.buildRouterFromPages(webDir);
58
+ fs.writeFileSync(path.join(routerDirPath, 'index.ts'), routerContent, 'utf8');
59
+ console.log('[web-adapter] 已创建路由配置');
60
+
61
+ // 5) 修补 app.ts:注册所有 Web 适配组件并挂载应用
62
+ appPatch.patchAppForWeb(webDir);
63
+ console.log('[web-adapter] 正在安装依赖项...');
64
+
65
+ // 如需安装依赖,可在此调用(默认跳过以加快生成速度)
66
+ // installDependencies(webDir);
67
+ } catch (err) {
68
+ console.error('[web-adapter] 生成 web 平台时出错:', err);
69
+ }
70
+ }
71
+
72
+ module.exports = { createWebPlatform };
73
+
74
+ if (require.main === module) {
75
+ createWebPlatform();
76
+ }
@@ -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
+ };