create-esmx 3.0.0-rc.46 → 3.0.0-rc.48
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/cli.mjs +10 -7
- package/package.json +4 -5
- package/src/cli.ts +12 -10
- package/template/vue-csr/README.md +80 -0
- package/template/vue-csr/package.json +26 -0
- package/template/vue-csr/src/app.vue +127 -0
- package/template/vue-csr/src/components/hello-world.vue +77 -0
- package/template/vue-csr/src/create-app.ts +9 -0
- package/template/vue-csr/src/entry.client.ts +5 -0
- package/template/vue-csr/src/entry.node.ts +35 -0
- package/template/vue-csr/src/entry.server.ts +26 -0
- package/template/vue-csr/tsconfig.json +26 -0
- package/template/vue-ssr/README.md +80 -0
- package/template/vue-ssr/package.json +27 -0
- package/template/vue-ssr/src/app.vue +127 -0
- package/template/vue-ssr/src/components/hello-world.vue +77 -0
- package/template/vue-ssr/src/create-app.ts +9 -0
- package/template/vue-ssr/src/entry.client.ts +5 -0
- package/template/vue-ssr/src/entry.node.ts +37 -0
- package/template/vue-ssr/src/entry.server.ts +30 -0
- package/template/vue-ssr/tsconfig.json +26 -0
- package/template/vue2-csr/README.md +2 -2
- package/template/vue2-csr/package.json +1 -1
- package/template/vue2-csr/src/components/hello-world.vue +1 -1
- package/template/vue2-csr/src/entry.node.ts +3 -0
- package/template/vue2-csr/src/entry.server.ts +2 -2
- package/template/vue2-ssr/package.json +1 -1
- package/template/vue2-ssr/src/entry.node.ts +3 -0
package/dist/cli.mjs
CHANGED
|
@@ -142,13 +142,16 @@ export async function cli(options = {}) {
|
|
|
142
142
|
);
|
|
143
143
|
const installCmd = installCommand;
|
|
144
144
|
const devCmd = devCommand;
|
|
145
|
-
const targetDirForDisplay = projectNameInput === "." ? "." :
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
];
|
|
145
|
+
const targetDirForDisplay = projectNameInput === "." ? "." : projectNameInput;
|
|
146
|
+
const steps = [
|
|
147
|
+
projectNameInput !== "." ? `cd ${targetDirForDisplay}` : null,
|
|
148
|
+
installCmd,
|
|
149
|
+
`git init ${color.gray("(optional)")}`,
|
|
150
|
+
devCmd
|
|
151
|
+
].filter(Boolean);
|
|
152
|
+
const nextSteps = steps.map((step, index) => {
|
|
153
|
+
return color.reset(`${index + 1}. ${color.cyan(step)}`);
|
|
154
|
+
});
|
|
152
155
|
note(nextSteps.join("\n"), "Next steps");
|
|
153
156
|
outro(color.reset(color.green("Happy coding! \u{1F389}")));
|
|
154
157
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-esmx",
|
|
3
|
-
"version": "3.0.0-rc.
|
|
3
|
+
"version": "3.0.0-rc.48",
|
|
4
4
|
"description": "A scaffold tool for creating Esmx projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -15,8 +15,7 @@
|
|
|
15
15
|
"coverage": "vitest run --coverage --pass-with-no-tests",
|
|
16
16
|
"lint:js": "biome check --write --no-errors-on-unmatched",
|
|
17
17
|
"build": "unbuild",
|
|
18
|
-
"postbuild": "node build/postbuild.mjs"
|
|
19
|
-
"export-templates": "node build/postbuild.mjs"
|
|
18
|
+
"postbuild": "node build/postbuild.mjs"
|
|
20
19
|
},
|
|
21
20
|
"dependencies": {
|
|
22
21
|
"@clack/prompts": "^0.7.0",
|
|
@@ -25,7 +24,7 @@
|
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@biomejs/biome": "1.9.4",
|
|
28
|
-
"@esmx/lint": "3.0.0-rc.
|
|
27
|
+
"@esmx/lint": "3.0.0-rc.48",
|
|
29
28
|
"@types/minimist": "^1.2.5",
|
|
30
29
|
"@types/node": "^24.0.0",
|
|
31
30
|
"@vitest/coverage-v8": "3.2.4",
|
|
@@ -70,5 +69,5 @@
|
|
|
70
69
|
"url": "https://github.com/esmnext/esmx/issues"
|
|
71
70
|
},
|
|
72
71
|
"homepage": "https://github.com/esmnext/esmx#readme",
|
|
73
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "162ec15d59c5f38c477e78101efa689844d593e2"
|
|
74
73
|
}
|
package/src/cli.ts
CHANGED
|
@@ -185,16 +185,18 @@ export async function cli(options: CliOptions = {}): Promise<void> {
|
|
|
185
185
|
const devCmd = devCommand;
|
|
186
186
|
|
|
187
187
|
const targetDirForDisplay =
|
|
188
|
-
projectNameInput === '.'
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
projectNameInput === '.' ? '.' : projectNameInput;
|
|
189
|
+
|
|
190
|
+
const steps = [
|
|
191
|
+
projectNameInput !== '.' ? `cd ${targetDirForDisplay}` : null,
|
|
192
|
+
installCmd,
|
|
193
|
+
`git init ${color.gray('(optional)')}`,
|
|
194
|
+
devCmd
|
|
195
|
+
].filter(Boolean);
|
|
196
|
+
|
|
197
|
+
const nextSteps = steps.map((step, index) => {
|
|
198
|
+
return color.reset(`${index + 1}. ${color.cyan(step)}`);
|
|
199
|
+
});
|
|
198
200
|
|
|
199
201
|
note(nextSteps.join('\n'), 'Next steps');
|
|
200
202
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
An Esmx project with Vue and Client-Side Rendering.
|
|
4
|
+
|
|
5
|
+
## 📦 Tech Stack
|
|
6
|
+
|
|
7
|
+
- **Framework**: [Esmx](https://esmnext.com) - Next generation micro-frontend framework based on native ESM
|
|
8
|
+
- **UI Framework**: Vue
|
|
9
|
+
- **Build Tool**: Rspack
|
|
10
|
+
- **Type Checking**: TypeScript
|
|
11
|
+
- **Rendering Mode**: Client-Side Rendering (CSR)
|
|
12
|
+
|
|
13
|
+
## 🚀 Quick Start
|
|
14
|
+
|
|
15
|
+
### Install Dependencies
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
{{installCommand}}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Development Environment
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
{{devCommand}}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Visit http://localhost:3000 to see the development environment.
|
|
28
|
+
|
|
29
|
+
### Production Build
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
{{buildCommand}}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Start Production Server
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
{{startCommand}}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Type Generation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
{{buildTypeCommand}}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Type Checking
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
{{lintTypeCommand}}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 📁 Project Structure
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
{{projectName}}/
|
|
57
|
+
├── src/
|
|
58
|
+
│ ├── app.vue # Main application component with Esmx and Vue logos
|
|
59
|
+
│ ├── components/ # UI components
|
|
60
|
+
│ │ └── hello-world.vue # Example component with counter functionality
|
|
61
|
+
│ ├── create-app.ts # Vue instance creation
|
|
62
|
+
│ ├── entry.client.ts # Client-side entry
|
|
63
|
+
│ ├── entry.node.ts # Node.js environment entry point
|
|
64
|
+
│ └── entry.server.ts # Server-side rendering functions
|
|
65
|
+
├── package.json
|
|
66
|
+
├── tsconfig.json
|
|
67
|
+
└── README.md
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 🔧 Configuration Details
|
|
71
|
+
|
|
72
|
+
- `entry.client.ts` - Responsible for client-side interaction and dynamic updates
|
|
73
|
+
- `entry.node.ts` - Handles server-side rendering and development server configuration
|
|
74
|
+
- `entry.server.ts` - Manages server-side rendering process and HTML generation
|
|
75
|
+
|
|
76
|
+
## 📚 Additional Resources
|
|
77
|
+
|
|
78
|
+
- [Esmx Official Documentation](https://esmnext.com)
|
|
79
|
+
- [Vue Documentation](https://vuejs.org)
|
|
80
|
+
- [TypeScript Documentation](https://www.typescriptlang.org)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vue Client-Side Rendering framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "esmx dev",
|
|
9
|
+
"build": "esmx build",
|
|
10
|
+
"preview": "esmx preview",
|
|
11
|
+
"start": "esmx start",
|
|
12
|
+
"lint:type": "vue-tsc --noEmit",
|
|
13
|
+
"build:type": "vue-tsc --declaration --emitDeclarationOnly --noEmit false --outDir dist/src && tsc-alias -p tsconfig.json --outDir dist/src"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@esmx/core": "{{esmxVersion}}"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"tsc-alias": "^1.8.16",
|
|
20
|
+
"@esmx/rspack-vue": "{{esmxVersion}}",
|
|
21
|
+
"@types/node": "^24.0.0",
|
|
22
|
+
"vue": "^3.5.18",
|
|
23
|
+
"typescript": "5.8.3",
|
|
24
|
+
"vue-tsc": "^3.0.1"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import HelloWorld from './components/hello-world.vue';
|
|
4
|
+
|
|
5
|
+
const title = ref<string>('Vue CSR Demo');
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div class="container">
|
|
10
|
+
<div class="logo-container">
|
|
11
|
+
<a href="https://www.esmnext.com" target="_blank" class="logo-link">
|
|
12
|
+
<div class="logo-wrapper esmx">
|
|
13
|
+
<img src="https://www.esmnext.com/logo.svg" class="logo" alt="Esmx logo" />
|
|
14
|
+
</div>
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://vuejs.org/" target="_blank" class="logo-link">
|
|
17
|
+
<div class="logo-wrapper vue">
|
|
18
|
+
<img src="https://vuejs.org/logo.svg" class="logo" alt="Vue logo" />
|
|
19
|
+
</div>
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
<HelloWorld :msg="title" />
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<style>
|
|
27
|
+
:root {
|
|
28
|
+
--esmx-primary: #001137;
|
|
29
|
+
--esmx-secondary: #273498;
|
|
30
|
+
--esmx-accent: #0074C2;
|
|
31
|
+
--esmx-light: #00ABE7;
|
|
32
|
+
--esmx-sun-core: #FFA000;
|
|
33
|
+
--esmx-sun-rays: #FFC107;
|
|
34
|
+
--vue-color: #42b883;
|
|
35
|
+
--vue-dark: #33a06f;
|
|
36
|
+
--border-color: rgba(0, 17, 55, 0.12);
|
|
37
|
+
--shadow-color: rgba(0, 17, 55, 0.05);
|
|
38
|
+
--text-primary: #213547;
|
|
39
|
+
--text-secondary: #666;
|
|
40
|
+
--bg-card: #fcfcfc;
|
|
41
|
+
--bg-hover: rgba(255, 250, 240, 0.8);
|
|
42
|
+
--font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
body {
|
|
46
|
+
margin: 0;
|
|
47
|
+
font-family: var(--font-family);
|
|
48
|
+
color: var(--text-primary);
|
|
49
|
+
background-color: white;
|
|
50
|
+
line-height: 1.6;
|
|
51
|
+
-webkit-font-smoothing: antialiased;
|
|
52
|
+
-moz-osx-font-smoothing: grayscale;
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.container {
|
|
58
|
+
max-width: 1280px;
|
|
59
|
+
margin: 0 auto;
|
|
60
|
+
padding: 2rem;
|
|
61
|
+
text-align: center;
|
|
62
|
+
font-family: var(--font-family);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.logo-container {
|
|
66
|
+
display: flex;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 3.5rem;
|
|
70
|
+
margin-bottom: 3rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.logo-link {
|
|
74
|
+
text-decoration: none;
|
|
75
|
+
position: relative;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.logo-wrapper {
|
|
79
|
+
display: flex;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
align-items: center;
|
|
82
|
+
width: 6.5em;
|
|
83
|
+
height: 6.5em;
|
|
84
|
+
border-radius: 12px;
|
|
85
|
+
background-color: var(--bg-card);
|
|
86
|
+
padding: 1em;
|
|
87
|
+
box-shadow: 0 2px 12px var(--shadow-color);
|
|
88
|
+
border: 1px solid var(--border-color);
|
|
89
|
+
transition: all 0.3s ease;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.logo-wrapper:hover {
|
|
93
|
+
transform: translateY(-5px);
|
|
94
|
+
box-shadow: 0 5px 15px var(--shadow-color);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.logo {
|
|
98
|
+
height: 100%;
|
|
99
|
+
width: auto;
|
|
100
|
+
transition: transform 0.3s ease;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.logo-wrapper:hover .logo {
|
|
104
|
+
transform: scale(1.1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.logo-wrapper.esmx:hover {
|
|
108
|
+
background-color: rgba(255, 192, 7, 0.1);
|
|
109
|
+
border-color: var(--esmx-sun-rays);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.logo-wrapper.vue:hover {
|
|
113
|
+
background-color: rgba(66, 184, 131, 0.1);
|
|
114
|
+
border-color: var(--vue-color);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (max-width: 768px) {
|
|
118
|
+
.logo-container {
|
|
119
|
+
gap: 2rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.logo-wrapper {
|
|
123
|
+
width: 5em;
|
|
124
|
+
height: 5em;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
defineProps({
|
|
5
|
+
msg: {
|
|
6
|
+
type: String
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
const count = ref<number>(0);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<div>
|
|
14
|
+
<h1>{{ msg }}</h1>
|
|
15
|
+
|
|
16
|
+
<div class="card">
|
|
17
|
+
<button type="button" @click="count++">Counter: {{ count }}</button>
|
|
18
|
+
<p>
|
|
19
|
+
Edit
|
|
20
|
+
<code>components/HelloWorld.vue</code> to test HMR
|
|
21
|
+
</p>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<p>Experience Vue with client-side rendering powered by Esmx framework</p>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<style scoped>
|
|
29
|
+
.card {
|
|
30
|
+
padding: 2em;
|
|
31
|
+
border-radius: 12px;
|
|
32
|
+
margin: 2.5em 0;
|
|
33
|
+
background-color: var(--bg-card);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
button {
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
border: 1px solid transparent;
|
|
39
|
+
padding: 0.6em 1.2em;
|
|
40
|
+
font-size: 1em;
|
|
41
|
+
font-weight: 600;
|
|
42
|
+
font-family: inherit;
|
|
43
|
+
background-color: var(--esmx-sun-rays);
|
|
44
|
+
color: #fff;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
margin-bottom: 1em;
|
|
47
|
+
transition: all 0.25s ease;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
button:hover {
|
|
51
|
+
background-color: var(--esmx-sun-core);
|
|
52
|
+
transform: translateY(-1px);
|
|
53
|
+
box-shadow: 0 4px 8px rgba(255, 160, 0, 0.25);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
h1 {
|
|
57
|
+
font-size: 3.2em;
|
|
58
|
+
line-height: 1.1;
|
|
59
|
+
margin-bottom: 1em;
|
|
60
|
+
color: var(--esmx-primary);
|
|
61
|
+
font-weight: 700;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
p {
|
|
65
|
+
line-height: 1.6;
|
|
66
|
+
margin: 0.5em 0;
|
|
67
|
+
color: var(--text-primary);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
code {
|
|
71
|
+
background-color: rgba(0, 116, 194, 0.1);
|
|
72
|
+
padding: 0.2em 0.4em;
|
|
73
|
+
border-radius: 4px;
|
|
74
|
+
font-family: monospace;
|
|
75
|
+
font-size: 0.9em;
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import type { EsmxOptions } from '@esmx/core';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
modules: {
|
|
6
|
+
exports: ['npm:vue']
|
|
7
|
+
},
|
|
8
|
+
async devApp(esmx) {
|
|
9
|
+
return import('@esmx/rspack-vue').then((m) =>
|
|
10
|
+
m.createRspackVue3App(esmx, {
|
|
11
|
+
chain(context) {
|
|
12
|
+
// Custom Rspack configuration
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
async postBuild(esmx) {
|
|
18
|
+
const rc = await esmx.render();
|
|
19
|
+
esmx.writeSync(esmx.resolvePath('dist/client', 'index.html'), rc.html);
|
|
20
|
+
},
|
|
21
|
+
async server(esmx) {
|
|
22
|
+
const server = http.createServer((req, res) => {
|
|
23
|
+
esmx.middleware(req, res, async () => {
|
|
24
|
+
const rc = await esmx.render({
|
|
25
|
+
params: { url: req.url }
|
|
26
|
+
});
|
|
27
|
+
res.end(rc.html);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
server.listen(3000, () => {
|
|
32
|
+
console.log('Server started: http://localhost:3000');
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
} satisfies EsmxOptions;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { RenderContext } from '@esmx/core';
|
|
2
|
+
|
|
3
|
+
export default async (rc: RenderContext) => {
|
|
4
|
+
await rc.commit();
|
|
5
|
+
|
|
6
|
+
rc.html = `<!DOCTYPE html>
|
|
7
|
+
<html lang="en">
|
|
8
|
+
<head>
|
|
9
|
+
<meta charset="UTF-8">
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
+
<meta name="description" content="Vue with Client-Side Rendering powered by Esmx framework">
|
|
12
|
+
<meta name="keywords" content="Vue, CSR, Client-Side Rendering, Esmx, Vue.js, JavaScript, TypeScript, Rspack">
|
|
13
|
+
<link rel="icon" href="https://www.esmnext.com/logo.svg" type="image/svg+xml">
|
|
14
|
+
${rc.preload()}
|
|
15
|
+
<title>Vue CSR Demo | Powered by Esmx</title>
|
|
16
|
+
${rc.css()}
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div id="app"></div>
|
|
20
|
+
${rc.importmap()}
|
|
21
|
+
${rc.moduleEntry()}
|
|
22
|
+
${rc.modulePreload()}
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
25
|
+
`;
|
|
26
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "ESNext",
|
|
4
|
+
"moduleResolution": "node",
|
|
5
|
+
"isolatedModules": true,
|
|
6
|
+
"resolveJsonModule": true,
|
|
7
|
+
|
|
8
|
+
"target": "ESNext",
|
|
9
|
+
"lib": ["ESNext", "DOM"],
|
|
10
|
+
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"types": ["@types/node"],
|
|
14
|
+
|
|
15
|
+
"experimentalDecorators": true,
|
|
16
|
+
"allowSyntheticDefaultImports": true,
|
|
17
|
+
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"paths": {
|
|
20
|
+
"{{projectName}}/src/*": ["./src/*"],
|
|
21
|
+
"{{projectName}}/*": ["./*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"],
|
|
25
|
+
"exclude": ["dist", "node_modules"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
An Esmx project with Vue and Server-Side Rendering.
|
|
4
|
+
|
|
5
|
+
## 📦 Tech Stack
|
|
6
|
+
|
|
7
|
+
- **Framework**: [Esmx](https://esmnext.com) - Next generation micro-frontend framework based on native ESM
|
|
8
|
+
- **UI Framework**: Vue
|
|
9
|
+
- **Build Tool**: Rspack
|
|
10
|
+
- **Type Checking**: TypeScript
|
|
11
|
+
- **Rendering Mode**: Server-Side Rendering (SSR)
|
|
12
|
+
|
|
13
|
+
## 🚀 Quick Start
|
|
14
|
+
|
|
15
|
+
### Install Dependencies
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
{{installCommand}}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Development Environment
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
{{devCommand}}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Visit http://localhost:3000 to see the development environment.
|
|
28
|
+
|
|
29
|
+
### Production Build
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
{{buildCommand}}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Start Production Server
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
{{startCommand}}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Type Generation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
{{buildTypeCommand}}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Type Checking
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
{{lintTypeCommand}}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 📁 Project Structure
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
{{projectName}}/
|
|
57
|
+
├── src/
|
|
58
|
+
│ ├── app.vue # Main application component with Esmx and Vue logos
|
|
59
|
+
│ ├── components/ # UI components
|
|
60
|
+
│ │ └── hello-world.vue # Example component with counter functionality
|
|
61
|
+
│ ├── create-app.ts # Vue instance creation
|
|
62
|
+
│ ├── entry.client.ts # Client-side entry
|
|
63
|
+
│ ├── entry.node.ts # Node.js environment entry point
|
|
64
|
+
│ └── entry.server.ts # Server-side rendering functions
|
|
65
|
+
├── package.json
|
|
66
|
+
├── tsconfig.json
|
|
67
|
+
└── README.md
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 🔧 Configuration Details
|
|
71
|
+
|
|
72
|
+
- `entry.client.ts` - Responsible for client-side interaction and dynamic updates
|
|
73
|
+
- `entry.node.ts` - Handles server-side rendering and development server configuration
|
|
74
|
+
- `entry.server.ts` - Manages server-side rendering process and HTML generation
|
|
75
|
+
|
|
76
|
+
## 📚 Additional Resources
|
|
77
|
+
|
|
78
|
+
- [Esmx Official Documentation](https://esmnext.com)
|
|
79
|
+
- [Vue Documentation](https://vuejs.org)
|
|
80
|
+
- [TypeScript Documentation](https://www.typescriptlang.org)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vue Server-Side Rendering framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": true,
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "esmx dev",
|
|
9
|
+
"build": "esmx build",
|
|
10
|
+
"preview": "esmx preview",
|
|
11
|
+
"start": "esmx start",
|
|
12
|
+
"lint:type": "vue-tsc --noEmit",
|
|
13
|
+
"build:type": "vue-tsc --declaration --emitDeclarationOnly --noEmit false --outDir dist/src && tsc-alias -p tsconfig.json --outDir dist/src"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@esmx/core": "{{esmxVersion}}"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"tsc-alias": "^1.8.16",
|
|
20
|
+
"@esmx/rspack-vue": "{{esmxVersion}}",
|
|
21
|
+
"@types/node": "^24.0.0",
|
|
22
|
+
"vue": "3.5.18",
|
|
23
|
+
"@vue/server-renderer": "3.5.18",
|
|
24
|
+
"typescript": "5.8.3",
|
|
25
|
+
"vue-tsc": "^3.0.1"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
import HelloWorld from './components/hello-world.vue';
|
|
4
|
+
|
|
5
|
+
const title = ref<string>('Vue SSR Demo');
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<div class="container">
|
|
10
|
+
<div class="logo-container">
|
|
11
|
+
<a href="https://www.esmnext.com" target="_blank" class="logo-link">
|
|
12
|
+
<div class="logo-wrapper esmx">
|
|
13
|
+
<img src="https://www.esmnext.com/logo.svg" class="logo" alt="Esmx logo" />
|
|
14
|
+
</div>
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://vuejs.org/" target="_blank" class="logo-link">
|
|
17
|
+
<div class="logo-wrapper vue">
|
|
18
|
+
<img src="https://vuejs.org/logo.svg" class="logo" alt="Vue logo" />
|
|
19
|
+
</div>
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
<HelloWorld :msg="title" />
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<style>
|
|
27
|
+
:root {
|
|
28
|
+
--esmx-primary: #001137;
|
|
29
|
+
--esmx-secondary: #273498;
|
|
30
|
+
--esmx-accent: #0074C2;
|
|
31
|
+
--esmx-light: #00ABE7;
|
|
32
|
+
--esmx-sun-core: #FFA000;
|
|
33
|
+
--esmx-sun-rays: #FFC107;
|
|
34
|
+
--vue-color: #42b883;
|
|
35
|
+
--vue-dark: #33a06f;
|
|
36
|
+
--border-color: rgba(0, 17, 55, 0.12);
|
|
37
|
+
--shadow-color: rgba(0, 17, 55, 0.05);
|
|
38
|
+
--text-primary: #213547;
|
|
39
|
+
--text-secondary: #666;
|
|
40
|
+
--bg-card: #fcfcfc;
|
|
41
|
+
--bg-hover: rgba(255, 250, 240, 0.8);
|
|
42
|
+
--font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
body {
|
|
46
|
+
margin: 0;
|
|
47
|
+
font-family: var(--font-family);
|
|
48
|
+
color: var(--text-primary);
|
|
49
|
+
background-color: white;
|
|
50
|
+
line-height: 1.6;
|
|
51
|
+
-webkit-font-smoothing: antialiased;
|
|
52
|
+
-moz-osx-font-smoothing: grayscale;
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.container {
|
|
58
|
+
max-width: 1280px;
|
|
59
|
+
margin: 0 auto;
|
|
60
|
+
padding: 2rem;
|
|
61
|
+
text-align: center;
|
|
62
|
+
font-family: var(--font-family);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.logo-container {
|
|
66
|
+
display: flex;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 3.5rem;
|
|
70
|
+
margin-bottom: 3rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.logo-link {
|
|
74
|
+
text-decoration: none;
|
|
75
|
+
position: relative;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.logo-wrapper {
|
|
79
|
+
display: flex;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
align-items: center;
|
|
82
|
+
width: 6.5em;
|
|
83
|
+
height: 6.5em;
|
|
84
|
+
border-radius: 12px;
|
|
85
|
+
background-color: var(--bg-card);
|
|
86
|
+
padding: 1em;
|
|
87
|
+
box-shadow: 0 2px 12px var(--shadow-color);
|
|
88
|
+
border: 1px solid var(--border-color);
|
|
89
|
+
transition: all 0.3s ease;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.logo-wrapper:hover {
|
|
93
|
+
transform: translateY(-5px);
|
|
94
|
+
box-shadow: 0 5px 15px var(--shadow-color);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.logo {
|
|
98
|
+
height: 100%;
|
|
99
|
+
width: auto;
|
|
100
|
+
transition: transform 0.3s ease;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.logo-wrapper:hover .logo {
|
|
104
|
+
transform: scale(1.1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.logo-wrapper.esmx:hover {
|
|
108
|
+
background-color: rgba(255, 192, 7, 0.1);
|
|
109
|
+
border-color: var(--esmx-sun-rays);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.logo-wrapper.vue:hover {
|
|
113
|
+
background-color: rgba(66, 184, 131, 0.1);
|
|
114
|
+
border-color: var(--vue-color);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (max-width: 768px) {
|
|
118
|
+
.logo-container {
|
|
119
|
+
gap: 2rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.logo-wrapper {
|
|
123
|
+
width: 5em;
|
|
124
|
+
height: 5em;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue';
|
|
3
|
+
|
|
4
|
+
defineProps({
|
|
5
|
+
msg: {
|
|
6
|
+
type: String
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
const count = ref<number>(0);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<div>
|
|
14
|
+
<h1>{{ msg }}</h1>
|
|
15
|
+
|
|
16
|
+
<div class="card">
|
|
17
|
+
<button type="button" @click="count++">Counter: {{ count }}</button>
|
|
18
|
+
<p>
|
|
19
|
+
Edit
|
|
20
|
+
<code>components/HelloWorld.vue</code> to test HMR
|
|
21
|
+
</p>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<p>Experience Vue with server-side rendering powered by Esmx framework</p>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<style scoped>
|
|
29
|
+
.card {
|
|
30
|
+
padding: 2em;
|
|
31
|
+
border-radius: 12px;
|
|
32
|
+
margin: 2.5em 0;
|
|
33
|
+
background-color: var(--bg-card);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
button {
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
border: 1px solid transparent;
|
|
39
|
+
padding: 0.6em 1.2em;
|
|
40
|
+
font-size: 1em;
|
|
41
|
+
font-weight: 600;
|
|
42
|
+
font-family: inherit;
|
|
43
|
+
background-color: var(--esmx-sun-rays);
|
|
44
|
+
color: #fff;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
margin-bottom: 1em;
|
|
47
|
+
transition: all 0.25s ease;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
button:hover {
|
|
51
|
+
background-color: var(--esmx-sun-core);
|
|
52
|
+
transform: translateY(-1px);
|
|
53
|
+
box-shadow: 0 4px 8px rgba(255, 160, 0, 0.25);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
h1 {
|
|
57
|
+
font-size: 3.2em;
|
|
58
|
+
line-height: 1.1;
|
|
59
|
+
margin-bottom: 1em;
|
|
60
|
+
color: var(--esmx-primary);
|
|
61
|
+
font-weight: 700;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
p {
|
|
65
|
+
line-height: 1.6;
|
|
66
|
+
margin: 0.5em 0;
|
|
67
|
+
color: var(--text-primary);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
code {
|
|
71
|
+
background-color: rgba(0, 116, 194, 0.1);
|
|
72
|
+
padding: 0.2em 0.4em;
|
|
73
|
+
border-radius: 4px;
|
|
74
|
+
font-family: monospace;
|
|
75
|
+
font-size: 0.9em;
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import type { EsmxOptions } from '@esmx/core';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
modules: {
|
|
6
|
+
exports: ['npm:vue']
|
|
7
|
+
},
|
|
8
|
+
async devApp(esmx) {
|
|
9
|
+
return import('@esmx/rspack-vue').then((m) =>
|
|
10
|
+
m.createRspackVue3App(esmx, {
|
|
11
|
+
chain(context) {
|
|
12
|
+
// Custom Rspack configuration
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
async postBuild(esmx) {
|
|
19
|
+
const rc = await esmx.render();
|
|
20
|
+
esmx.writeSync(esmx.resolvePath('dist/client', 'index.html'), rc.html);
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
async server(esmx) {
|
|
24
|
+
const server = http.createServer((req, res) => {
|
|
25
|
+
esmx.middleware(req, res, async () => {
|
|
26
|
+
const rc = await esmx.render({
|
|
27
|
+
params: { url: req.url }
|
|
28
|
+
});
|
|
29
|
+
res.end(rc.html);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
server.listen(3000, () => {
|
|
34
|
+
console.log('Server started: http://localhost:3000');
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
} satisfies EsmxOptions;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RenderContext } from '@esmx/core';
|
|
2
|
+
import { renderToString } from '@vue/server-renderer';
|
|
3
|
+
import { createVueApp } from './create-app';
|
|
4
|
+
|
|
5
|
+
export default async (rc: RenderContext) => {
|
|
6
|
+
const { app } = createVueApp();
|
|
7
|
+
const html = await renderToString(app);
|
|
8
|
+
await rc.commit();
|
|
9
|
+
|
|
10
|
+
rc.html = `<!DOCTYPE html>
|
|
11
|
+
<html lang="en">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="UTF-8">
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
15
|
+
<meta name="description" content="Vue with Server-Side Rendering powered by Esmx framework">
|
|
16
|
+
<meta name="keywords" content="Vue, SSR, Server-Side Rendering, Esmx, Vue.js, JavaScript, TypeScript, Rspack">
|
|
17
|
+
<link rel="icon" href="https://www.esmnext.com/logo.svg" type="image/svg+xml">
|
|
18
|
+
${rc.preload()}
|
|
19
|
+
<title>Vue SSR Demo | Powered by Esmx</title>
|
|
20
|
+
${rc.css()}
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<div id="app">${html}</div>
|
|
24
|
+
${rc.importmap()}
|
|
25
|
+
${rc.moduleEntry()}
|
|
26
|
+
${rc.modulePreload()}
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
29
|
+
`;
|
|
30
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "ESNext",
|
|
4
|
+
"moduleResolution": "node",
|
|
5
|
+
"isolatedModules": true,
|
|
6
|
+
"resolveJsonModule": true,
|
|
7
|
+
|
|
8
|
+
"target": "ESNext",
|
|
9
|
+
"lib": ["ESNext", "DOM"],
|
|
10
|
+
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"types": ["@types/node"],
|
|
14
|
+
|
|
15
|
+
"experimentalDecorators": true,
|
|
16
|
+
"allowSyntheticDefaultImports": true,
|
|
17
|
+
|
|
18
|
+
"baseUrl": ".",
|
|
19
|
+
"paths": {
|
|
20
|
+
"{{projectName}}/src/*": ["./src/*"],
|
|
21
|
+
"{{projectName}}/*": ["./*"]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"],
|
|
25
|
+
"exclude": ["dist", "node_modules"]
|
|
26
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# {{projectName}}
|
|
2
2
|
|
|
3
|
-
An Esmx project with Vue2 and
|
|
3
|
+
An Esmx project with Vue2 and Client-Side Rendering.
|
|
4
4
|
|
|
5
5
|
## 📦 Tech Stack
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ An Esmx project with Vue2 and Server-Side Rendering.
|
|
|
8
8
|
- **UI Framework**: Vue2 with Composition API
|
|
9
9
|
- **Build Tool**: Rspack
|
|
10
10
|
- **Type Checking**: TypeScript
|
|
11
|
-
- **Rendering Mode**:
|
|
11
|
+
- **Rendering Mode**: Client-Side Rendering (CSR)
|
|
12
12
|
|
|
13
13
|
## 🚀 Quick Start
|
|
14
14
|
|
|
@@ -8,8 +8,8 @@ export default async (rc: RenderContext) => {
|
|
|
8
8
|
<head>
|
|
9
9
|
<meta charset="UTF-8">
|
|
10
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
-
<meta name="description" content="Vue2 with
|
|
12
|
-
<meta name="keywords" content="Vue2, CSR,
|
|
11
|
+
<meta name="description" content="Vue2 with Client-Side Rendering powered by Esmx framework">
|
|
12
|
+
<meta name="keywords" content="Vue2, CSR, Client-Side Rendering, Esmx, Vue.js, JavaScript, TypeScript, Rspack">
|
|
13
13
|
<link rel="icon" href="https://www.esmnext.com/logo.svg" type="image/svg+xml">
|
|
14
14
|
${rc.preload()}
|
|
15
15
|
<title>Vue2 CSR Demo | Powered by Esmx</title>
|