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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/README.zh-CN.md +52 -0
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.integration.test.d.ts +1 -0
  6. package/dist/cli.integration.test.mjs +238 -0
  7. package/dist/cli.mjs +166 -0
  8. package/dist/create.d.ts +2 -0
  9. package/dist/create.mjs +6 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.mjs +2 -0
  12. package/dist/project.d.ts +5 -0
  13. package/dist/project.mjs +46 -0
  14. package/dist/project.test.d.ts +1 -0
  15. package/dist/project.test.mjs +155 -0
  16. package/dist/template.d.ts +17 -0
  17. package/dist/template.mjs +76 -0
  18. package/dist/template.test.d.ts +1 -0
  19. package/dist/template.test.mjs +106 -0
  20. package/dist/types.d.ts +30 -0
  21. package/dist/types.mjs +0 -0
  22. package/dist/utils/index.d.ts +3 -0
  23. package/dist/utils/index.mjs +7 -0
  24. package/dist/utils/package-manager.d.ts +10 -0
  25. package/dist/utils/package-manager.mjs +49 -0
  26. package/dist/utils/package-manager.test.d.ts +4 -0
  27. package/dist/utils/package-manager.test.mjs +275 -0
  28. package/dist/utils/project-name.d.ts +48 -0
  29. package/dist/utils/project-name.mjs +42 -0
  30. package/dist/utils/project-name.test.d.ts +1 -0
  31. package/dist/utils/project-name.test.mjs +332 -0
  32. package/dist/utils/template.d.ts +19 -0
  33. package/dist/utils/template.mjs +8 -0
  34. package/dist/utils/template.test.d.ts +4 -0
  35. package/dist/utils/template.test.mjs +150 -0
  36. package/package.json +75 -0
  37. package/src/cli.integration.test.ts +289 -0
  38. package/src/cli.ts +214 -0
  39. package/src/create.ts +8 -0
  40. package/src/index.ts +3 -0
  41. package/src/project.test.ts +200 -0
  42. package/src/project.ts +75 -0
  43. package/src/template.test.ts +135 -0
  44. package/src/template.ts +117 -0
  45. package/src/types.ts +32 -0
  46. package/src/utils/index.ts +11 -0
  47. package/src/utils/package-manager.test.ts +540 -0
  48. package/src/utils/package-manager.ts +92 -0
  49. package/src/utils/project-name.test.ts +441 -0
  50. package/src/utils/project-name.ts +101 -0
  51. package/src/utils/template.test.ts +234 -0
  52. package/src/utils/template.ts +34 -0
  53. package/template/react-csr/README.md +81 -0
  54. package/template/react-csr/package.json +29 -0
  55. package/template/react-csr/src/app.css +98 -0
  56. package/template/react-csr/src/app.tsx +26 -0
  57. package/template/react-csr/src/components/hello-world.css +48 -0
  58. package/template/react-csr/src/components/hello-world.tsx +29 -0
  59. package/template/react-csr/src/create-app.tsx +9 -0
  60. package/template/react-csr/src/entry.client.ts +13 -0
  61. package/template/react-csr/src/entry.node.ts +35 -0
  62. package/template/react-csr/src/entry.server.tsx +27 -0
  63. package/template/react-csr/tsconfig.json +27 -0
  64. package/template/react-ssr/README.md +81 -0
  65. package/template/react-ssr/package.json +29 -0
  66. package/template/react-ssr/src/app.css +98 -0
  67. package/template/react-ssr/src/app.tsx +26 -0
  68. package/template/react-ssr/src/components/hello-world.css +48 -0
  69. package/template/react-ssr/src/components/hello-world.tsx +29 -0
  70. package/template/react-ssr/src/create-app.tsx +9 -0
  71. package/template/react-ssr/src/entry.client.ts +13 -0
  72. package/template/react-ssr/src/entry.node.ts +32 -0
  73. package/template/react-ssr/src/entry.server.tsx +36 -0
  74. package/template/react-ssr/tsconfig.json +27 -0
  75. package/template/shared-modules/README.md +85 -0
  76. package/template/shared-modules/package.json +28 -0
  77. package/template/shared-modules/src/entry.client.ts +50 -0
  78. package/template/shared-modules/src/entry.node.ts +67 -0
  79. package/template/shared-modules/src/entry.server.ts +299 -0
  80. package/template/shared-modules/src/index.ts +3 -0
  81. package/template/shared-modules/src/vue/index.ts +1 -0
  82. package/template/shared-modules/src/vue2/index.ts +1 -0
  83. package/template/shared-modules/tsconfig.json +26 -0
  84. package/template/vue-csr/README.md +80 -0
  85. package/template/vue-csr/package.json +26 -0
  86. package/template/vue-csr/src/app.vue +127 -0
  87. package/template/vue-csr/src/components/hello-world.vue +77 -0
  88. package/template/vue-csr/src/create-app.ts +9 -0
  89. package/template/vue-csr/src/entry.client.ts +5 -0
  90. package/template/vue-csr/src/entry.node.ts +35 -0
  91. package/template/vue-csr/src/entry.server.ts +26 -0
  92. package/template/vue-csr/tsconfig.json +26 -0
  93. package/template/vue-ssr/README.md +80 -0
  94. package/template/vue-ssr/package.json +27 -0
  95. package/template/vue-ssr/src/app.vue +127 -0
  96. package/template/vue-ssr/src/components/hello-world.vue +77 -0
  97. package/template/vue-ssr/src/create-app.ts +9 -0
  98. package/template/vue-ssr/src/entry.client.ts +5 -0
  99. package/template/vue-ssr/src/entry.node.ts +37 -0
  100. package/template/vue-ssr/src/entry.server.ts +30 -0
  101. package/template/vue-ssr/tsconfig.json +26 -0
  102. package/template/vue2-csr/README.md +80 -0
  103. package/template/vue2-csr/package.json +26 -0
  104. package/template/vue2-csr/src/app.vue +127 -0
  105. package/template/vue2-csr/src/components/hello-world.vue +77 -0
  106. package/template/vue2-csr/src/create-app.ts +11 -0
  107. package/template/vue2-csr/src/entry.client.ts +5 -0
  108. package/template/vue2-csr/src/entry.node.ts +35 -0
  109. package/template/vue2-csr/src/entry.server.ts +26 -0
  110. package/template/vue2-csr/tsconfig.json +26 -0
  111. package/template/vue2-ssr/README.md +80 -0
  112. package/template/vue2-ssr/package.json +27 -0
  113. package/template/vue2-ssr/src/app.vue +127 -0
  114. package/template/vue2-ssr/src/components/hello-world.vue +77 -0
  115. package/template/vue2-ssr/src/create-app.ts +11 -0
  116. package/template/vue2-ssr/src/entry.client.ts +5 -0
  117. package/template/vue2-ssr/src/entry.node.ts +32 -0
  118. package/template/vue2-ssr/src/entry.server.ts +37 -0
  119. package/template/vue2-ssr/tsconfig.json +26 -0
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Unit tests for template variable replacement utilities
3
+ */
4
+
5
+ import { describe, expect, it } from 'vitest';
6
+ import { replaceTemplateVariables } from './template';
7
+
8
+ describe('replaceTemplateVariables', () => {
9
+ describe('basic functionality', () => {
10
+ it('should replace single variable', () => {
11
+ // Arrange
12
+ const content = 'Hello {{name}}!';
13
+ const variables = { name: 'World' };
14
+
15
+ // Act
16
+ const result = replaceTemplateVariables(content, variables);
17
+
18
+ // Assert
19
+ expect(result).toBe('Hello World!');
20
+ });
21
+
22
+ it('should replace multiple different variables', () => {
23
+ // Arrange
24
+ const content = 'Project {{projectName}} version {{version}}';
25
+ const variables = {
26
+ projectName: 'my-app',
27
+ version: '1.0.0'
28
+ };
29
+
30
+ // Act
31
+ const result = replaceTemplateVariables(content, variables);
32
+
33
+ // Assert
34
+ expect(result).toBe('Project my-app version 1.0.0');
35
+ });
36
+
37
+ it('should replace same variable multiple times', () => {
38
+ // Arrange
39
+ const content = '{{greeting}} {{name}}, {{greeting}} again!';
40
+ const variables = {
41
+ greeting: 'Hello',
42
+ name: 'World'
43
+ };
44
+
45
+ // Act
46
+ const result = replaceTemplateVariables(content, variables);
47
+
48
+ // Assert
49
+ expect(result).toBe('Hello World, Hello again!');
50
+ });
51
+ });
52
+
53
+ describe('edge cases', () => {
54
+ it('should handle content without variables', () => {
55
+ // Arrange
56
+ const content = 'No variables here';
57
+ const variables = { name: 'World' };
58
+
59
+ // Act
60
+ const result = replaceTemplateVariables(content, variables);
61
+
62
+ // Assert
63
+ expect(result).toBe('No variables here');
64
+ });
65
+
66
+ it('should handle empty variables object', () => {
67
+ // Arrange
68
+ const content = 'Hello {{name}}!';
69
+ const variables = {};
70
+
71
+ // Act
72
+ const result = replaceTemplateVariables(content, variables);
73
+
74
+ // Assert
75
+ expect(result).toBe('Hello {{name}}!');
76
+ });
77
+
78
+ it('should handle empty content', () => {
79
+ // Arrange
80
+ const content = '';
81
+ const variables = { name: 'World' };
82
+
83
+ // Act
84
+ const result = replaceTemplateVariables(content, variables);
85
+
86
+ // Assert
87
+ expect(result).toBe('');
88
+ });
89
+
90
+ it('should handle variables with special characters', () => {
91
+ // Arrange
92
+ const content = 'Command: {{installCommand}}';
93
+ const variables = { installCommand: 'npm install --save-dev' };
94
+
95
+ // Act
96
+ const result = replaceTemplateVariables(content, variables);
97
+
98
+ // Assert
99
+ expect(result).toBe('Command: npm install --save-dev');
100
+ });
101
+
102
+ it('should handle variables with regex special characters', () => {
103
+ // Arrange
104
+ const content = 'Pattern: {{pattern}}';
105
+ const variables = { pattern: '[a-z]+.*$' };
106
+
107
+ // Act
108
+ const result = replaceTemplateVariables(content, variables);
109
+
110
+ // Assert
111
+ expect(result).toBe('Pattern: [a-z]+.*$');
112
+ });
113
+ });
114
+
115
+ describe('real-world scenarios', () => {
116
+ it('should handle all template variables from create-esmx', () => {
117
+ // Arrange
118
+ const content = `# {{projectName}}
119
+
120
+ Install dependencies:
121
+ \`\`\`bash
122
+ {{installCommand}}
123
+ \`\`\`
124
+
125
+ Start development:
126
+ \`\`\`bash
127
+ {{devCommand}}
128
+ \`\`\`
129
+
130
+ Build for production:
131
+ \`\`\`bash
132
+ {{buildCommand}}
133
+ \`\`\`
134
+
135
+ Start production server:
136
+ \`\`\`bash
137
+ {{startCommand}}
138
+ \`\`\`
139
+
140
+ Esmx version: {{esmxVersion}}`;
141
+
142
+ const variables = {
143
+ projectName: 'my-awesome-app',
144
+ installCommand: 'pnpm install',
145
+ devCommand: 'pnpm dev',
146
+ buildCommand: 'pnpm build',
147
+ startCommand: 'pnpm start',
148
+ esmxVersion: '3.0.0-rc.33'
149
+ };
150
+
151
+ // Act
152
+ const result = replaceTemplateVariables(content, variables);
153
+
154
+ // Assert
155
+ expect(result).toContain('# my-awesome-app');
156
+ expect(result).toContain('pnpm install');
157
+ expect(result).toContain('pnpm dev');
158
+ expect(result).toContain('pnpm build');
159
+ expect(result).toContain('pnpm start');
160
+ expect(result).toContain('3.0.0-rc.33');
161
+ expect(result).not.toContain('{{');
162
+ expect(result).not.toContain('}}');
163
+ });
164
+
165
+ it('should handle package.json template', () => {
166
+ // Arrange
167
+ const content = `{
168
+ "name": "{{projectName}}",
169
+ "version": "1.0.0",
170
+ "scripts": {
171
+ "dev": "esmx dev",
172
+ "build": "esmx build",
173
+ "start": "esmx start"
174
+ },
175
+ "dependencies": {
176
+ "esmx": "{{esmxVersion}}"
177
+ }
178
+ }`;
179
+
180
+ const variables = {
181
+ projectName: '@scope/my-package',
182
+ esmxVersion: '^3.0.0'
183
+ };
184
+
185
+ // Act
186
+ const result = replaceTemplateVariables(content, variables);
187
+
188
+ // Assert
189
+ expect(result).toContain('"name": "@scope/my-package"');
190
+ expect(result).toContain('"esmx": "^3.0.0"');
191
+ });
192
+ });
193
+
194
+ describe('variable name validation', () => {
195
+ it('should handle variables with underscores', () => {
196
+ // Arrange
197
+ const content = 'Command: {{install_command}}';
198
+ const variables = { install_command: 'npm install' };
199
+
200
+ // Act
201
+ const result = replaceTemplateVariables(content, variables);
202
+
203
+ // Assert
204
+ expect(result).toBe('Command: npm install');
205
+ });
206
+
207
+ it('should handle variables with numbers', () => {
208
+ // Arrange
209
+ const content = 'Node version: {{node18}}';
210
+ const variables = { node18: 'v18.12.0' };
211
+
212
+ // Act
213
+ const result = replaceTemplateVariables(content, variables);
214
+
215
+ // Assert
216
+ expect(result).toBe('Node version: v18.12.0');
217
+ });
218
+
219
+ it('should be case sensitive', () => {
220
+ // Arrange
221
+ const content = 'Hello {{Name}} and {{name}}!';
222
+ const variables = {
223
+ Name: 'Alice',
224
+ name: 'Bob'
225
+ };
226
+
227
+ // Act
228
+ const result = replaceTemplateVariables(content, variables);
229
+
230
+ // Assert
231
+ expect(result).toBe('Hello Alice and Bob!');
232
+ });
233
+ });
234
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Template variable replacement utilities
3
+ */
4
+
5
+ /**
6
+ * Replace template variables in content using mustache-style syntax {{variableName}}
7
+ *
8
+ * @param content - The content string containing template variables
9
+ * @param variables - Object containing variable names and their replacement values
10
+ * @returns Content with all template variables replaced
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const content = "Hello {{name}}, version {{version}}!";
15
+ * const variables = { name: "World", version: "1.0.0" };
16
+ * const result = replaceTemplateVariables(content, variables);
17
+ * // Result: "Hello World, version 1.0.0!"
18
+ * ```
19
+ */
20
+ export function replaceTemplateVariables(
21
+ content: string,
22
+ variables: Record<string, string>
23
+ ): string {
24
+ let result = content;
25
+
26
+ // Iterate through all variables and replace them
27
+ for (const [key, value] of Object.entries(variables)) {
28
+ // Create regex pattern for {{variableName}} with global flag
29
+ const pattern = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
30
+ result = result.replace(pattern, value);
31
+ }
32
+
33
+ return result;
34
+ }
@@ -0,0 +1,81 @@
1
+ # {{projectName}}
2
+
3
+ An Esmx project with React and Client-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**: 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.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 # CSR HTML shell (no SSR)
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 development environment setup and tooling
74
+ - `entry.server.tsx` - Generates the HTML shell for CSR (no SSR)
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 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": "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 CSR 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 client-side rendering powered by Esmx framework</p>
26
+ </div>
27
+ );
28
+ }
29
+
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import App from './app';
3
+
4
+ export function createApp() {
5
+ return {
6
+ app: <App />
7
+ };
8
+ }
9
+
@@ -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,35 @@
1
+ import http from 'node:http';
2
+ import type { EsmxOptions } from '@esmx/core';
3
+
4
+ export default {
5
+ modules: {
6
+ exports: ['pkg:react']
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
+ 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,27 @@
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="React with Client-Side Rendering powered by Esmx framework">
12
+ <meta name="keywords" content="React, CSR, Client-Side Rendering, Esmx, React.js, JavaScript, TypeScript, Rspack">
13
+ <link rel="icon" href="https://esmx.dev/logo.svg" type="image/svg+xml">
14
+ ${rc.preload()}
15
+ <title>React 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
+ };
27
+
@@ -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
+