create-esmx 3.0.0-rc.104
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/LICENSE +21 -0
- package/README.md +52 -0
- package/README.zh-CN.md +52 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.integration.test.d.ts +1 -0
- package/dist/cli.integration.test.mjs +238 -0
- package/dist/cli.mjs +166 -0
- package/dist/create.d.ts +2 -0
- package/dist/create.mjs +6 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +2 -0
- package/dist/project.d.ts +5 -0
- package/dist/project.mjs +46 -0
- package/dist/project.test.d.ts +1 -0
- package/dist/project.test.mjs +155 -0
- package/dist/template.d.ts +17 -0
- package/dist/template.mjs +76 -0
- package/dist/template.test.d.ts +1 -0
- package/dist/template.test.mjs +106 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.mjs +0 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.mjs +7 -0
- package/dist/utils/package-manager.d.ts +10 -0
- package/dist/utils/package-manager.mjs +49 -0
- package/dist/utils/package-manager.test.d.ts +4 -0
- package/dist/utils/package-manager.test.mjs +275 -0
- package/dist/utils/project-name.d.ts +48 -0
- package/dist/utils/project-name.mjs +42 -0
- package/dist/utils/project-name.test.d.ts +1 -0
- package/dist/utils/project-name.test.mjs +332 -0
- package/dist/utils/template.d.ts +19 -0
- package/dist/utils/template.mjs +8 -0
- package/dist/utils/template.test.d.ts +4 -0
- package/dist/utils/template.test.mjs +150 -0
- package/package.json +75 -0
- package/src/cli.integration.test.ts +289 -0
- package/src/cli.ts +214 -0
- package/src/create.ts +8 -0
- package/src/index.ts +3 -0
- package/src/project.test.ts +200 -0
- package/src/project.ts +75 -0
- package/src/template.test.ts +135 -0
- package/src/template.ts +117 -0
- package/src/types.ts +32 -0
- package/src/utils/index.ts +11 -0
- package/src/utils/package-manager.test.ts +540 -0
- package/src/utils/package-manager.ts +92 -0
- package/src/utils/project-name.test.ts +441 -0
- package/src/utils/project-name.ts +101 -0
- package/src/utils/template.test.ts +234 -0
- package/src/utils/template.ts +34 -0
- package/template/react-csr/README.md +81 -0
- package/template/react-csr/package.json +29 -0
- package/template/react-csr/src/app.css +98 -0
- package/template/react-csr/src/app.tsx +26 -0
- package/template/react-csr/src/components/hello-world.css +48 -0
- package/template/react-csr/src/components/hello-world.tsx +29 -0
- package/template/react-csr/src/create-app.tsx +9 -0
- package/template/react-csr/src/entry.client.ts +13 -0
- package/template/react-csr/src/entry.node.ts +35 -0
- package/template/react-csr/src/entry.server.tsx +27 -0
- package/template/react-csr/tsconfig.json +27 -0
- package/template/react-ssr/README.md +81 -0
- package/template/react-ssr/package.json +29 -0
- package/template/react-ssr/src/app.css +98 -0
- package/template/react-ssr/src/app.tsx +26 -0
- package/template/react-ssr/src/components/hello-world.css +48 -0
- package/template/react-ssr/src/components/hello-world.tsx +29 -0
- package/template/react-ssr/src/create-app.tsx +9 -0
- package/template/react-ssr/src/entry.client.ts +13 -0
- package/template/react-ssr/src/entry.node.ts +32 -0
- package/template/react-ssr/src/entry.server.tsx +36 -0
- package/template/react-ssr/tsconfig.json +27 -0
- package/template/shared-modules/README.md +85 -0
- package/template/shared-modules/package.json +28 -0
- package/template/shared-modules/src/entry.client.ts +50 -0
- package/template/shared-modules/src/entry.node.ts +67 -0
- package/template/shared-modules/src/entry.server.ts +299 -0
- package/template/shared-modules/src/index.ts +3 -0
- package/template/shared-modules/src/vue/index.ts +1 -0
- package/template/shared-modules/src/vue2/index.ts +1 -0
- package/template/shared-modules/tsconfig.json +26 -0
- 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 +80 -0
- package/template/vue2-csr/package.json +26 -0
- package/template/vue2-csr/src/app.vue +127 -0
- package/template/vue2-csr/src/components/hello-world.vue +77 -0
- package/template/vue2-csr/src/create-app.ts +11 -0
- package/template/vue2-csr/src/entry.client.ts +5 -0
- package/template/vue2-csr/src/entry.node.ts +35 -0
- package/template/vue2-csr/src/entry.server.ts +26 -0
- package/template/vue2-csr/tsconfig.json +26 -0
- package/template/vue2-ssr/README.md +80 -0
- package/template/vue2-ssr/package.json +27 -0
- package/template/vue2-ssr/src/app.vue +127 -0
- package/template/vue2-ssr/src/components/hello-world.vue +77 -0
- package/template/vue2-ssr/src/create-app.ts +11 -0
- package/template/vue2-ssr/src/entry.client.ts +5 -0
- package/template/vue2-ssr/src/entry.node.ts +32 -0
- package/template/vue2-ssr/src/entry.server.ts +37 -0
- package/template/vue2-ssr/tsconfig.json +26 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
An Esmx project with React and Server-Side Rendering.
|
|
4
|
+
|
|
5
|
+
## 📦 Tech Stack
|
|
6
|
+
|
|
7
|
+
- **Framework**: [Esmx](https://esmx.dev) - Next generation micro-frontend framework based on native ESM
|
|
8
|
+
- **UI Framework**: React 18
|
|
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.tsx # Main application component with Esmx and React logos
|
|
59
|
+
│ ├── components/ # UI components
|
|
60
|
+
│ │ └── hello-world.tsx # Example component with counter functionality
|
|
61
|
+
│ ├── create-app.tsx # React app instance creation
|
|
62
|
+
│ ├── entry.client.ts # Client-side entry
|
|
63
|
+
│ ├── entry.node.ts # Node.js environment entry point
|
|
64
|
+
│ └── entry.server.tsx # 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.tsx` - Manages server-side rendering process and HTML generation
|
|
75
|
+
|
|
76
|
+
## 📚 Additional Resources
|
|
77
|
+
|
|
78
|
+
- [Esmx Official Documentation](https://esmx.dev)
|
|
79
|
+
- [React Documentation](https://react.dev)
|
|
80
|
+
- [TypeScript Documentation](https://www.typescriptlang.org)
|
|
81
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "React 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": "tsc --noEmit",
|
|
13
|
+
"build:type": "tsc --declaration --emitDeclarationOnly --outDir dist/src && tsc-alias -p tsconfig.json --outDir dist/src"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@esmx/core": "{{esmxVersion}}",
|
|
17
|
+
"react": "^18.0.0",
|
|
18
|
+
"react-dom": "^18.0.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"tsc-alias": "^1.8.16",
|
|
22
|
+
"@esmx/rspack-react": "{{esmxVersion}}",
|
|
23
|
+
"@types/node": "^24.0.0",
|
|
24
|
+
"@types/react": "^18.0.0",
|
|
25
|
+
"@types/react-dom": "^18.0.0",
|
|
26
|
+
"typescript": "5.8.3"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--esmx-primary: #001137;
|
|
3
|
+
--esmx-secondary: #273498;
|
|
4
|
+
--esmx-accent: #0074c2;
|
|
5
|
+
--esmx-light: #00abe7;
|
|
6
|
+
--esmx-sun-core: #ffa000;
|
|
7
|
+
--esmx-sun-rays: #ffc107;
|
|
8
|
+
--react-color: #61dafb;
|
|
9
|
+
--react-dark: #20232a;
|
|
10
|
+
--border-color: rgba(0, 17, 55, 0.12);
|
|
11
|
+
--shadow-color: rgba(0, 17, 55, 0.05);
|
|
12
|
+
--text-primary: #213547;
|
|
13
|
+
--text-secondary: #666;
|
|
14
|
+
--bg-card: #fcfcfc;
|
|
15
|
+
--bg-hover: rgba(255, 250, 240, 0.8);
|
|
16
|
+
--font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
body {
|
|
20
|
+
margin: 0;
|
|
21
|
+
font-family: var(--font-family);
|
|
22
|
+
color: var(--text-primary);
|
|
23
|
+
background-color: white;
|
|
24
|
+
line-height: 1.6;
|
|
25
|
+
-webkit-font-smoothing: antialiased;
|
|
26
|
+
-moz-osx-font-smoothing: grayscale;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.container {
|
|
30
|
+
max-width: 1280px;
|
|
31
|
+
margin: 0 auto;
|
|
32
|
+
padding: 2rem;
|
|
33
|
+
text-align: center;
|
|
34
|
+
font-family: var(--font-family);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.logo-container {
|
|
38
|
+
display: flex;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: 3.5rem;
|
|
42
|
+
margin-bottom: 3rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.logo-link {
|
|
46
|
+
text-decoration: none;
|
|
47
|
+
position: relative;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.logo-wrapper {
|
|
51
|
+
display: flex;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
align-items: center;
|
|
54
|
+
width: 6.5em;
|
|
55
|
+
height: 6.5em;
|
|
56
|
+
border-radius: 12px;
|
|
57
|
+
background-color: var(--bg-card);
|
|
58
|
+
padding: 1em;
|
|
59
|
+
box-shadow: 0 2px 12px var(--shadow-color);
|
|
60
|
+
border: 1px solid var(--border-color);
|
|
61
|
+
transition: all 0.3s ease;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.logo-wrapper:hover {
|
|
65
|
+
transform: translateY(-5px);
|
|
66
|
+
box-shadow: 0 5px 15px var(--shadow-color);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.logo {
|
|
70
|
+
height: 100%;
|
|
71
|
+
width: auto;
|
|
72
|
+
transition: transform 0.3s ease;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.logo-wrapper:hover .logo {
|
|
76
|
+
transform: scale(1.1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.logo-wrapper.esmx:hover {
|
|
80
|
+
background-color: rgba(255, 192, 7, 0.1);
|
|
81
|
+
border-color: var(--esmx-sun-rays);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.logo-wrapper.react:hover {
|
|
85
|
+
background-color: rgba(97, 218, 251, 0.1);
|
|
86
|
+
border-color: var(--react-color);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@media (max-width: 768px) {
|
|
90
|
+
.logo-container {
|
|
91
|
+
gap: 2rem;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.logo-wrapper {
|
|
95
|
+
width: 5em;
|
|
96
|
+
height: 5em;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import HelloWorld from './components/hello-world';
|
|
3
|
+
import './app.css';
|
|
4
|
+
|
|
5
|
+
export default function App() {
|
|
6
|
+
const title = 'React SSR Demo';
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div id="app" className="container">
|
|
10
|
+
<div className="logo-container">
|
|
11
|
+
<a href="https://esmx.dev" target="_blank" rel="noopener noreferrer" className="logo-link">
|
|
12
|
+
<div className="logo-wrapper esmx">
|
|
13
|
+
<img src="https://esmx.dev/logo.svg" className="logo" alt="Esmx logo" />
|
|
14
|
+
</div>
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://react.dev/" target="_blank" rel="noopener noreferrer" className="logo-link">
|
|
17
|
+
<div className="logo-wrapper react">
|
|
18
|
+
<img src="https://react.dev/favicon-192x192.png" className="logo" alt="React logo" />
|
|
19
|
+
</div>
|
|
20
|
+
</a>
|
|
21
|
+
</div>
|
|
22
|
+
<HelloWorld msg={title} />
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
.card {
|
|
2
|
+
padding: 2em;
|
|
3
|
+
border-radius: 12px;
|
|
4
|
+
margin: 2.5em 0;
|
|
5
|
+
background-color: var(--bg-card);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
button {
|
|
9
|
+
border-radius: 8px;
|
|
10
|
+
border: 1px solid transparent;
|
|
11
|
+
padding: 0.6em 1.2em;
|
|
12
|
+
font-size: 1em;
|
|
13
|
+
font-weight: 600;
|
|
14
|
+
font-family: inherit;
|
|
15
|
+
background-color: var(--esmx-sun-rays);
|
|
16
|
+
color: #fff;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
margin-bottom: 1em;
|
|
19
|
+
transition: all 0.25s ease;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
button:hover {
|
|
23
|
+
background-color: var(--esmx-sun-core);
|
|
24
|
+
transform: translateY(-1px);
|
|
25
|
+
box-shadow: 0 4px 8px rgba(255, 160, 0, 0.25);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
h1 {
|
|
29
|
+
font-size: 3.2em;
|
|
30
|
+
line-height: 1.1;
|
|
31
|
+
margin-bottom: 1em;
|
|
32
|
+
color: var(--esmx-primary);
|
|
33
|
+
font-weight: 700;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
p {
|
|
37
|
+
line-height: 1.6;
|
|
38
|
+
margin: 0.5em 0;
|
|
39
|
+
color: var(--text-primary);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
code {
|
|
43
|
+
background-color: rgba(0, 116, 194, 0.1);
|
|
44
|
+
padding: 0.2em 0.4em;
|
|
45
|
+
border-radius: 4px;
|
|
46
|
+
font-family: monospace;
|
|
47
|
+
font-size: 0.9em;
|
|
48
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import './hello-world.css';
|
|
3
|
+
|
|
4
|
+
interface HelloWorldProps {
|
|
5
|
+
msg: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function HelloWorld({ msg }: HelloWorldProps) {
|
|
9
|
+
const [count, setCount] = useState<number>(0);
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div>
|
|
13
|
+
<h1>{msg}</h1>
|
|
14
|
+
|
|
15
|
+
<div className="card">
|
|
16
|
+
<button type="button" onClick={() => setCount(count + 1)}>
|
|
17
|
+
Counter: {count}
|
|
18
|
+
</button>
|
|
19
|
+
<p>
|
|
20
|
+
Edit
|
|
21
|
+
<code>components/HelloWorld.tsx</code> to test HMR
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<p>Experience React with server-side rendering powered by Esmx framework</p>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { createApp } from './create-app';
|
|
4
|
+
|
|
5
|
+
const { app } = createApp();
|
|
6
|
+
|
|
7
|
+
const container = document.getElementById('app');
|
|
8
|
+
if (container) {
|
|
9
|
+
const root = createRoot(container);
|
|
10
|
+
root.render(app);
|
|
11
|
+
} else {
|
|
12
|
+
console.error('Container element #app not found');
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import type { EsmxOptions } from '@esmx/core';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
modules: {
|
|
6
|
+
exports: []
|
|
7
|
+
},
|
|
8
|
+
async devApp(esmx) {
|
|
9
|
+
return import('@esmx/rspack-react').then((m) =>
|
|
10
|
+
m.createRspackReactApp(esmx, {
|
|
11
|
+
config(context) {
|
|
12
|
+
// Custom Rspack configuration
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
async server(esmx) {
|
|
19
|
+
const server = http.createServer((req, res) => {
|
|
20
|
+
esmx.middleware(req, res, async () => {
|
|
21
|
+
const rc = await esmx.render({
|
|
22
|
+
params: { url: req.url }
|
|
23
|
+
});
|
|
24
|
+
res.end(rc.html);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
server.listen(3000, () => {
|
|
29
|
+
console.log('Server started: http://localhost:3000');
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
} satisfies EsmxOptions;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RenderContext } from '@esmx/core';
|
|
2
|
+
import { renderToString } from 'react-dom/server';
|
|
3
|
+
import { createApp } from './create-app';
|
|
4
|
+
|
|
5
|
+
export default async (rc: RenderContext) => {
|
|
6
|
+
// Create React app instance
|
|
7
|
+
const { app } = createApp();
|
|
8
|
+
|
|
9
|
+
// Use React's renderToString to generate page content
|
|
10
|
+
const html = renderToString(app);
|
|
11
|
+
|
|
12
|
+
// Commit dependency collection to ensure all necessary resources are loaded
|
|
13
|
+
await rc.commit();
|
|
14
|
+
|
|
15
|
+
// Generate complete HTML structure
|
|
16
|
+
rc.html = `<!DOCTYPE html>
|
|
17
|
+
<html lang="en">
|
|
18
|
+
<head>
|
|
19
|
+
<meta charset="UTF-8">
|
|
20
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
21
|
+
<meta name="description" content="React with Server-Side Rendering powered by Esmx framework">
|
|
22
|
+
<meta name="keywords" content="React, SSR, Server-Side Rendering, Esmx, React.js, JavaScript, TypeScript, Rspack">
|
|
23
|
+
<link rel="icon" href="https://esmx.dev/logo.svg" type="image/svg+xml">
|
|
24
|
+
${rc.preload()}
|
|
25
|
+
<title>React SSR Demo | Powered by Esmx</title>
|
|
26
|
+
${rc.css()}
|
|
27
|
+
</head>
|
|
28
|
+
<body>
|
|
29
|
+
<div id="app">${html}</div>
|
|
30
|
+
${rc.importmap()}
|
|
31
|
+
${rc.moduleEntry()}
|
|
32
|
+
${rc.modulePreload()}
|
|
33
|
+
</body>
|
|
34
|
+
</html>`;
|
|
35
|
+
};
|
|
36
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
"jsx": "react-jsx",
|
|
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
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# {{projectName}}
|
|
2
|
+
|
|
3
|
+
An Esmx project demonstrating Shared Modules solution for micro-frontend architecture.
|
|
4
|
+
|
|
5
|
+
## 📦 Tech Stack
|
|
6
|
+
|
|
7
|
+
- **Framework**: [Esmx](https://esmx.dev) - Next generation micro-frontend framework based on native ESM
|
|
8
|
+
- **Solution Focus**: Shared Modules for multi-framework environments
|
|
9
|
+
- **Build Tool**: Rspack
|
|
10
|
+
- **Type Checking**: TypeScript
|
|
11
|
+
|
|
12
|
+
## 🎯 Core Features
|
|
13
|
+
|
|
14
|
+
- **Module Sharing**: Share modules across different framework versions
|
|
15
|
+
- **Zero Overhead**: Native ESM-based sharing with no runtime cost
|
|
16
|
+
- **Version Isolation**: Safe module sharing between framework versions
|
|
17
|
+
- **SSR Compatible**: Full server-side rendering support with shared modules
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
### Install Dependencies
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
{{installCommand}}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Development Environment
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
{{devCommand}}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Visit http://localhost:3000 to see the development environment.
|
|
34
|
+
|
|
35
|
+
### Production Build
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
{{buildCommand}}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Start Production Server
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
{{startCommand}}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Type Generation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
{{buildTypeCommand}}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Type Checking
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
{{lintTypeCommand}}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 📁 Project Structure
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
{{projectName}}/
|
|
63
|
+
├── src/
|
|
64
|
+
│ ├── entry.client.ts # Client-side entry
|
|
65
|
+
│ ├── entry.node.ts # Node.js environment entry point
|
|
66
|
+
│ ├── entry.server.ts # Server-side rendering functions
|
|
67
|
+
│ ├── vue/
|
|
68
|
+
│ │ └── index.ts # Vue 3 shared modules
|
|
69
|
+
│ └── vue2/
|
|
70
|
+
│ └── index.ts # Vue 2 shared modules
|
|
71
|
+
├── package.json
|
|
72
|
+
├── tsconfig.json
|
|
73
|
+
└── README.md
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 🔧 Configuration Details
|
|
77
|
+
|
|
78
|
+
- `entry.client.ts` - Responsible for client-side shared module consistency checking
|
|
79
|
+
- `entry.node.ts` - Handles shared module configuration and scope mapping
|
|
80
|
+
- `entry.server.ts` - Manages shared module rendering and HTML generation
|
|
81
|
+
|
|
82
|
+
## 📚 Additional Resources
|
|
83
|
+
|
|
84
|
+
- [Esmx Official Documentation](https://esmx.dev)
|
|
85
|
+
- [TypeScript Documentation](https://www.typescriptlang.org)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared modules solution for micro-frontend architecture",
|
|
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": "tsc --noEmit",
|
|
13
|
+
"build:type": "tsc --declaration --emitDeclarationOnly --outDir dist/src && tsc-alias -p tsconfig.json --outDir dist/src"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@esmx/core": "{{esmxVersion}}"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"vue": "^3.5.23",
|
|
20
|
+
"@esmx/router": "{{esmxVersion}}",
|
|
21
|
+
"@esmx/router-vue": "{{esmxVersion}}",
|
|
22
|
+
"vue2": "npm:vue@2.7.16",
|
|
23
|
+
"tsc-alias": "^1.8.16",
|
|
24
|
+
"@esmx/rspack": "{{esmxVersion}}",
|
|
25
|
+
"@types/node": "^24.10.0",
|
|
26
|
+
"typescript": "5.9.3"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { version } from './vue/index';
|
|
2
|
+
import { version as vue2Version } from './vue2/index';
|
|
3
|
+
|
|
4
|
+
const versions = [
|
|
5
|
+
{ name: 'vue3', clientVersion: version },
|
|
6
|
+
{ name: 'vue2', clientVersion: vue2Version }
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
function checkVersionConsistency() {
|
|
10
|
+
versions.forEach(({ name, clientVersion }) => {
|
|
11
|
+
const serverVersion = document.getElementById(
|
|
12
|
+
`${name}-server-version`
|
|
13
|
+
)?.textContent;
|
|
14
|
+
const status = document.getElementById(`${name}-status`);
|
|
15
|
+
const card = document.getElementById(`${name}-card`);
|
|
16
|
+
|
|
17
|
+
const clientVersionEl = document.getElementById(
|
|
18
|
+
`${name}-client-version`
|
|
19
|
+
);
|
|
20
|
+
if (clientVersionEl) clientVersionEl.textContent = clientVersion;
|
|
21
|
+
|
|
22
|
+
if (!status || !card) return;
|
|
23
|
+
|
|
24
|
+
const isConsistent = clientVersion === serverVersion;
|
|
25
|
+
status.className = `status-indicator status-${
|
|
26
|
+
isConsistent ? 'consistent' : 'inconsistent'
|
|
27
|
+
}`;
|
|
28
|
+
const icon = status.querySelector('.icon');
|
|
29
|
+
const text = status.querySelector('span:not(.icon)');
|
|
30
|
+
if (icon) {
|
|
31
|
+
icon.className = `icon ${isConsistent ? 'success' : 'error'}`;
|
|
32
|
+
icon.textContent = isConsistent ? '✓' : '✗';
|
|
33
|
+
}
|
|
34
|
+
if (text) {
|
|
35
|
+
text.textContent = `Module versions ${
|
|
36
|
+
isConsistent ? 'consistent' : 'inconsistent'
|
|
37
|
+
}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (isConsistent) {
|
|
41
|
+
card.classList.add('consistency-animation');
|
|
42
|
+
setTimeout(
|
|
43
|
+
() => card.classList.remove('consistency-animation'),
|
|
44
|
+
2000
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
checkVersionConsistency();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import type { EsmxOptions } from '@esmx/core';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
modules: {
|
|
6
|
+
exports: [
|
|
7
|
+
// ========== Applicable to all shared modules ==========
|
|
8
|
+
'pkg:@esmx/router',
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
// ========== Vue framework shared module configuration ==========
|
|
12
|
+
// Business code: import Vue from 'vue' (defaults to Vue 3, shared from common modules)
|
|
13
|
+
vue: {
|
|
14
|
+
client: 'pkg:vue/dist/vue.runtime.esm-browser.prod.js', // Vue 3 production
|
|
15
|
+
server: 'pkg:vue/dist/vue.runtime.esm-browser.js' // Vue 3 development
|
|
16
|
+
},
|
|
17
|
+
'vue/index': 'root:src/vue/index.ts',
|
|
18
|
+
'@esmx/router-vue': 'pkg:@esmx/router-vue', // Vue 3 router
|
|
19
|
+
|
|
20
|
+
// ========== Vue2 framework shared module configuration ==========
|
|
21
|
+
// Exported to vue2/ directory, version isolation via scope mapping
|
|
22
|
+
vue2: 'pkg:vue2/dist/vue.runtime.esm.js', // → vue2/vue.mjs
|
|
23
|
+
'vue2/@esmx/router-vue': 'pkg:@esmx/router-vue', // → vue2/@esmx/router-vue.mjs,
|
|
24
|
+
'vue2/index': 'root:src/vue2/index.ts'
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
|
|
28
|
+
scopes: {
|
|
29
|
+
// ========== Vue2 shared module scope mapping ==========
|
|
30
|
+
// Directory scope mapping: Only affects shared modules in vue2/ directory
|
|
31
|
+
// Business code in vue2/ directory: import Vue from 'vue' → {{projectName}}/vue2 (version-isolated)
|
|
32
|
+
// Business code in other directories: import Vue from 'vue' → Vue 3 (shared from common modules)
|
|
33
|
+
'vue2/': {
|
|
34
|
+
vue: '{{projectName}}/vue2'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Package scope mapping: Affects dependencies within shared module packages
|
|
38
|
+
// Example: When 'vue' package depends on 'AA', use replacement version
|
|
39
|
+
// 'vue': {
|
|
40
|
+
// AA: 'some-other-AA'
|
|
41
|
+
// }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
async devApp(esmx) {
|
|
45
|
+
return import('@esmx/rspack').then((m) =>
|
|
46
|
+
m.createRspackHtmlApp(esmx, {
|
|
47
|
+
chain(context) {
|
|
48
|
+
// Custom Rspack configuration
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
async server(esmx) {
|
|
54
|
+
const server = http.createServer((req, res) => {
|
|
55
|
+
esmx.middleware(req, res, async () => {
|
|
56
|
+
const rc = await esmx.render({
|
|
57
|
+
params: { url: req.url }
|
|
58
|
+
});
|
|
59
|
+
res.end(rc.html);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
server.listen(3000, () => {
|
|
64
|
+
console.log('Server started: http://localhost:3000');
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
} satisfies EsmxOptions;
|