@bleedingdev/modern-js-ultramodern-sandpack-profile 3.8.3-ultramodern.2
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/dist/cjs/index.cjs +261 -0
- package/dist/esm/index.js +223 -0
- package/dist/esm-node/index.js +224 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +51 -0
- package/rslib.config.mts +4 -0
- package/src/index.ts +241 -0
- package/tests/profile-build.smoke.ts +99 -0
- package/tests/profile.test.ts +106 -0
- package/tsconfig.json +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-present Modern.js
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
const packageJson = `${JSON.stringify({
|
|
31
|
+
name: 'ultramodern-sandpack-app',
|
|
32
|
+
version: '0.1.0',
|
|
33
|
+
private: true,
|
|
34
|
+
type: 'module',
|
|
35
|
+
packageManager: 'pnpm@11.24.0',
|
|
36
|
+
scripts: {
|
|
37
|
+
dev: 'modern dev',
|
|
38
|
+
start: 'modern dev --host 0.0.0.0',
|
|
39
|
+
build: 'modern build'
|
|
40
|
+
},
|
|
41
|
+
engines: {
|
|
42
|
+
node: '>=26.7.0',
|
|
43
|
+
pnpm: '>=11.24.0'
|
|
44
|
+
},
|
|
45
|
+
dependencies: {
|
|
46
|
+
'@modern-js/plugin-i18n': 'npm:@bleedingdev/modern-js-plugin-i18n@latest',
|
|
47
|
+
'@modern-js/plugin-tanstack': 'npm:@bleedingdev/modern-js-plugin-tanstack@latest',
|
|
48
|
+
'@modern-js/runtime': 'npm:@bleedingdev/modern-js-runtime@latest',
|
|
49
|
+
effect: '4.0.0-rc.112',
|
|
50
|
+
i18next: '26.3.6',
|
|
51
|
+
react: '19.2.8',
|
|
52
|
+
'react-dom': '19.2.8'
|
|
53
|
+
},
|
|
54
|
+
devDependencies: {
|
|
55
|
+
'@modern-js/app-tools': 'npm:@bleedingdev/modern-js-app-tools@latest',
|
|
56
|
+
'@modern-js/tsconfig': 'npm:@bleedingdev/modern-js-tsconfig@latest',
|
|
57
|
+
'@rsbuild/plugin-tailwindcss': '2.0.3',
|
|
58
|
+
'@types/node': '^26.2.0',
|
|
59
|
+
'@types/react': '^19.2.18',
|
|
60
|
+
'@types/react-dom': '^19.2.4',
|
|
61
|
+
tailwindcss: '4.3.3',
|
|
62
|
+
typescript: '7.0.2'
|
|
63
|
+
}
|
|
64
|
+
}, null, 2)}\n`;
|
|
65
|
+
const codeSandboxTasks = `${JSON.stringify({
|
|
66
|
+
$schema: 'https://codesandbox.io/schemas/tasks.json',
|
|
67
|
+
setupTasks: [
|
|
68
|
+
{
|
|
69
|
+
name: 'Installing dependencies',
|
|
70
|
+
command: 'pnpm install'
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
tasks: {
|
|
74
|
+
start: {
|
|
75
|
+
name: 'UltraModern.js application',
|
|
76
|
+
command: 'pnpm start',
|
|
77
|
+
runAtStart: true,
|
|
78
|
+
preview: {
|
|
79
|
+
port: 8080,
|
|
80
|
+
prLink: 'direct'
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}, null, 2)}\n`;
|
|
85
|
+
const modernConfig = `import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
86
|
+
import { i18nPlugin } from '@modern-js/plugin-i18n';
|
|
87
|
+
import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
|
|
88
|
+
import { pluginTailwindcss } from '@rsbuild/plugin-tailwindcss';
|
|
89
|
+
|
|
90
|
+
export default defineConfig({
|
|
91
|
+
builderPlugins: [pluginTailwindcss()],
|
|
92
|
+
output: {
|
|
93
|
+
disableTsChecker: false,
|
|
94
|
+
polyfill: 'off',
|
|
95
|
+
},
|
|
96
|
+
performance: {
|
|
97
|
+
buildCache: false,
|
|
98
|
+
},
|
|
99
|
+
plugins: [
|
|
100
|
+
appTools(),
|
|
101
|
+
tanstackRouterPlugin(),
|
|
102
|
+
i18nPlugin({
|
|
103
|
+
htmlLangAttr: true,
|
|
104
|
+
localeDetection: {
|
|
105
|
+
fallbackLanguage: 'en',
|
|
106
|
+
languages: ['en', 'cs'],
|
|
107
|
+
localePathRedirect: false,
|
|
108
|
+
},
|
|
109
|
+
reactI18next: false,
|
|
110
|
+
}),
|
|
111
|
+
],
|
|
112
|
+
server: {
|
|
113
|
+
ssr: false,
|
|
114
|
+
},
|
|
115
|
+
source: {
|
|
116
|
+
alias: {
|
|
117
|
+
'@modern-js/plugin-i18n/runtime':
|
|
118
|
+
'@modern-js/plugin-i18n/runtime/no-react-i18next',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
`;
|
|
123
|
+
const runtimeConfig = `import { defineRuntimeConfig } from '@modern-js/runtime';
|
|
124
|
+
import { createInstance } from 'i18next';
|
|
125
|
+
|
|
126
|
+
const i18nInstance = createInstance();
|
|
127
|
+
|
|
128
|
+
export default defineRuntimeConfig({
|
|
129
|
+
i18n: {
|
|
130
|
+
i18nInstance,
|
|
131
|
+
initOptions: {
|
|
132
|
+
defaultNS: 'translation',
|
|
133
|
+
fallbackLng: 'en',
|
|
134
|
+
lng: 'en',
|
|
135
|
+
resources: {
|
|
136
|
+
en: {
|
|
137
|
+
translation: {
|
|
138
|
+
language: 'Language',
|
|
139
|
+
welcome: 'Build a fast, typed UltraModern.js application.',
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
cs: {
|
|
143
|
+
translation: {
|
|
144
|
+
language: 'Jazyk',
|
|
145
|
+
welcome: 'Vytvořte rychlou a typově bezpečnou UltraModern.js aplikaci.',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
supportedLngs: ['en', 'cs'],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
router: {
|
|
153
|
+
framework: 'tanstack',
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
`;
|
|
157
|
+
const layout = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
158
|
+
import { Link, Outlet } from '@modern-js/plugin-tanstack/runtime';
|
|
159
|
+
|
|
160
|
+
export default function Layout() {
|
|
161
|
+
const { changeLanguage, language, t } = useModernI18n();
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className="min-h-screen bg-slate-950 text-slate-100">
|
|
165
|
+
<header className="mx-auto flex max-w-4xl items-center justify-between p-6">
|
|
166
|
+
<Link className="font-semibold" prefetch="render" to="/">
|
|
167
|
+
UltraModern.js
|
|
168
|
+
</Link>
|
|
169
|
+
<label className="flex items-center gap-2 text-sm">
|
|
170
|
+
{t('language')}
|
|
171
|
+
<select
|
|
172
|
+
aria-label={t('language')}
|
|
173
|
+
className="rounded bg-slate-800 px-2 py-1"
|
|
174
|
+
onChange={event => void changeLanguage(event.currentTarget.value)}
|
|
175
|
+
value={language}
|
|
176
|
+
>
|
|
177
|
+
<option value="en">English</option>
|
|
178
|
+
<option value="cs">Čeština</option>
|
|
179
|
+
</select>
|
|
180
|
+
</label>
|
|
181
|
+
</header>
|
|
182
|
+
<Outlet />
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
`;
|
|
187
|
+
const page = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
188
|
+
import { Effect, pipe } from 'effect';
|
|
189
|
+
import './index.css';
|
|
190
|
+
|
|
191
|
+
export default function HomePage() {
|
|
192
|
+
const { language, t } = useModernI18n();
|
|
193
|
+
const message = Effect.runSync(
|
|
194
|
+
pipe(
|
|
195
|
+
Effect.succeed(t('welcome')),
|
|
196
|
+
Effect.map(text => \`\${text} [\${language}]\`),
|
|
197
|
+
),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<main className="mx-auto max-w-4xl px-6 py-20">
|
|
202
|
+
<p className="text-sm font-medium uppercase tracking-widest text-cyan-300">
|
|
203
|
+
Effect · TanStack Router · Tailwind · i18n
|
|
204
|
+
</p>
|
|
205
|
+
<h1 className="mt-4 text-5xl font-bold tracking-tight">{message}</h1>
|
|
206
|
+
<p className="mt-6 text-slate-300">
|
|
207
|
+
Edit <code>src/routes/page.tsx</code> to get started.
|
|
208
|
+
</p>
|
|
209
|
+
</main>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
`;
|
|
213
|
+
const ultramodernSandpackFiles = {
|
|
214
|
+
'/.browserslistrc': 'defaults\n',
|
|
215
|
+
'/.codesandbox/environment.json': '{\n "nodeVersion": "26"\n}\n',
|
|
216
|
+
'/.codesandbox/tasks.json': codeSandboxTasks,
|
|
217
|
+
'/modern.config.ts': modernConfig,
|
|
218
|
+
'/package.json': packageJson,
|
|
219
|
+
'/src/modern-app-env.d.ts': '/// <reference types="@modern-js/app-tools/types" />\n',
|
|
220
|
+
'/src/modern.runtime.ts': runtimeConfig,
|
|
221
|
+
'/src/routes/index.css': `@import 'tailwindcss' source(none);
|
|
222
|
+
@source '..';
|
|
223
|
+
|
|
224
|
+
html {
|
|
225
|
+
color-scheme: dark;
|
|
226
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
body {
|
|
230
|
+
margin: 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
* {
|
|
234
|
+
box-sizing: border-box;
|
|
235
|
+
}
|
|
236
|
+
`,
|
|
237
|
+
'/src/routes/layout.tsx': layout,
|
|
238
|
+
'/src/routes/page.tsx': page,
|
|
239
|
+
'/tsconfig.json': `${JSON.stringify({
|
|
240
|
+
extends: '@modern-js/tsconfig/base',
|
|
241
|
+
compilerOptions: {
|
|
242
|
+
jsx: 'react-jsx',
|
|
243
|
+
noUncheckedIndexedAccess: true,
|
|
244
|
+
strict: true
|
|
245
|
+
},
|
|
246
|
+
include: [
|
|
247
|
+
'src',
|
|
248
|
+
'modern.config.ts'
|
|
249
|
+
]
|
|
250
|
+
}, null, 2)}\n`
|
|
251
|
+
};
|
|
252
|
+
__webpack_require__.d(__webpack_exports__, {}, {
|
|
253
|
+
ultramodernSandpackFiles: ultramodernSandpackFiles
|
|
254
|
+
});
|
|
255
|
+
exports.ultramodernSandpackFiles = __webpack_exports__.ultramodernSandpackFiles;
|
|
256
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
257
|
+
"ultramodernSandpackFiles"
|
|
258
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
259
|
+
Object.defineProperty(exports, '__esModule', {
|
|
260
|
+
value: true
|
|
261
|
+
});
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
const packageJson = `${JSON.stringify({
|
|
2
|
+
name: 'ultramodern-sandpack-app',
|
|
3
|
+
version: '0.1.0',
|
|
4
|
+
private: true,
|
|
5
|
+
type: 'module',
|
|
6
|
+
packageManager: 'pnpm@11.24.0',
|
|
7
|
+
scripts: {
|
|
8
|
+
dev: 'modern dev',
|
|
9
|
+
start: 'modern dev --host 0.0.0.0',
|
|
10
|
+
build: 'modern build'
|
|
11
|
+
},
|
|
12
|
+
engines: {
|
|
13
|
+
node: '>=26.7.0',
|
|
14
|
+
pnpm: '>=11.24.0'
|
|
15
|
+
},
|
|
16
|
+
dependencies: {
|
|
17
|
+
'@modern-js/plugin-i18n': 'npm:@bleedingdev/modern-js-plugin-i18n@latest',
|
|
18
|
+
'@modern-js/plugin-tanstack': 'npm:@bleedingdev/modern-js-plugin-tanstack@latest',
|
|
19
|
+
'@modern-js/runtime': 'npm:@bleedingdev/modern-js-runtime@latest',
|
|
20
|
+
effect: '4.0.0-rc.112',
|
|
21
|
+
i18next: '26.3.6',
|
|
22
|
+
react: '19.2.8',
|
|
23
|
+
'react-dom': '19.2.8'
|
|
24
|
+
},
|
|
25
|
+
devDependencies: {
|
|
26
|
+
'@modern-js/app-tools': 'npm:@bleedingdev/modern-js-app-tools@latest',
|
|
27
|
+
'@modern-js/tsconfig': 'npm:@bleedingdev/modern-js-tsconfig@latest',
|
|
28
|
+
'@rsbuild/plugin-tailwindcss': '2.0.3',
|
|
29
|
+
'@types/node': '^26.2.0',
|
|
30
|
+
'@types/react': '^19.2.18',
|
|
31
|
+
'@types/react-dom': '^19.2.4',
|
|
32
|
+
tailwindcss: '4.3.3',
|
|
33
|
+
typescript: '7.0.2'
|
|
34
|
+
}
|
|
35
|
+
}, null, 2)}\n`;
|
|
36
|
+
const codeSandboxTasks = `${JSON.stringify({
|
|
37
|
+
$schema: 'https://codesandbox.io/schemas/tasks.json',
|
|
38
|
+
setupTasks: [
|
|
39
|
+
{
|
|
40
|
+
name: 'Installing dependencies',
|
|
41
|
+
command: 'pnpm install'
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
tasks: {
|
|
45
|
+
start: {
|
|
46
|
+
name: 'UltraModern.js application',
|
|
47
|
+
command: 'pnpm start',
|
|
48
|
+
runAtStart: true,
|
|
49
|
+
preview: {
|
|
50
|
+
port: 8080,
|
|
51
|
+
prLink: 'direct'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}, null, 2)}\n`;
|
|
56
|
+
const modernConfig = `import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
57
|
+
import { i18nPlugin } from '@modern-js/plugin-i18n';
|
|
58
|
+
import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
|
|
59
|
+
import { pluginTailwindcss } from '@rsbuild/plugin-tailwindcss';
|
|
60
|
+
|
|
61
|
+
export default defineConfig({
|
|
62
|
+
builderPlugins: [pluginTailwindcss()],
|
|
63
|
+
output: {
|
|
64
|
+
disableTsChecker: false,
|
|
65
|
+
polyfill: 'off',
|
|
66
|
+
},
|
|
67
|
+
performance: {
|
|
68
|
+
buildCache: false,
|
|
69
|
+
},
|
|
70
|
+
plugins: [
|
|
71
|
+
appTools(),
|
|
72
|
+
tanstackRouterPlugin(),
|
|
73
|
+
i18nPlugin({
|
|
74
|
+
htmlLangAttr: true,
|
|
75
|
+
localeDetection: {
|
|
76
|
+
fallbackLanguage: 'en',
|
|
77
|
+
languages: ['en', 'cs'],
|
|
78
|
+
localePathRedirect: false,
|
|
79
|
+
},
|
|
80
|
+
reactI18next: false,
|
|
81
|
+
}),
|
|
82
|
+
],
|
|
83
|
+
server: {
|
|
84
|
+
ssr: false,
|
|
85
|
+
},
|
|
86
|
+
source: {
|
|
87
|
+
alias: {
|
|
88
|
+
'@modern-js/plugin-i18n/runtime':
|
|
89
|
+
'@modern-js/plugin-i18n/runtime/no-react-i18next',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
`;
|
|
94
|
+
const runtimeConfig = `import { defineRuntimeConfig } from '@modern-js/runtime';
|
|
95
|
+
import { createInstance } from 'i18next';
|
|
96
|
+
|
|
97
|
+
const i18nInstance = createInstance();
|
|
98
|
+
|
|
99
|
+
export default defineRuntimeConfig({
|
|
100
|
+
i18n: {
|
|
101
|
+
i18nInstance,
|
|
102
|
+
initOptions: {
|
|
103
|
+
defaultNS: 'translation',
|
|
104
|
+
fallbackLng: 'en',
|
|
105
|
+
lng: 'en',
|
|
106
|
+
resources: {
|
|
107
|
+
en: {
|
|
108
|
+
translation: {
|
|
109
|
+
language: 'Language',
|
|
110
|
+
welcome: 'Build a fast, typed UltraModern.js application.',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
cs: {
|
|
114
|
+
translation: {
|
|
115
|
+
language: 'Jazyk',
|
|
116
|
+
welcome: 'Vytvořte rychlou a typově bezpečnou UltraModern.js aplikaci.',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
supportedLngs: ['en', 'cs'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
router: {
|
|
124
|
+
framework: 'tanstack',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
`;
|
|
128
|
+
const layout = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
129
|
+
import { Link, Outlet } from '@modern-js/plugin-tanstack/runtime';
|
|
130
|
+
|
|
131
|
+
export default function Layout() {
|
|
132
|
+
const { changeLanguage, language, t } = useModernI18n();
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<div className="min-h-screen bg-slate-950 text-slate-100">
|
|
136
|
+
<header className="mx-auto flex max-w-4xl items-center justify-between p-6">
|
|
137
|
+
<Link className="font-semibold" prefetch="render" to="/">
|
|
138
|
+
UltraModern.js
|
|
139
|
+
</Link>
|
|
140
|
+
<label className="flex items-center gap-2 text-sm">
|
|
141
|
+
{t('language')}
|
|
142
|
+
<select
|
|
143
|
+
aria-label={t('language')}
|
|
144
|
+
className="rounded bg-slate-800 px-2 py-1"
|
|
145
|
+
onChange={event => void changeLanguage(event.currentTarget.value)}
|
|
146
|
+
value={language}
|
|
147
|
+
>
|
|
148
|
+
<option value="en">English</option>
|
|
149
|
+
<option value="cs">Čeština</option>
|
|
150
|
+
</select>
|
|
151
|
+
</label>
|
|
152
|
+
</header>
|
|
153
|
+
<Outlet />
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
`;
|
|
158
|
+
const page = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
159
|
+
import { Effect, pipe } from 'effect';
|
|
160
|
+
import './index.css';
|
|
161
|
+
|
|
162
|
+
export default function HomePage() {
|
|
163
|
+
const { language, t } = useModernI18n();
|
|
164
|
+
const message = Effect.runSync(
|
|
165
|
+
pipe(
|
|
166
|
+
Effect.succeed(t('welcome')),
|
|
167
|
+
Effect.map(text => \`\${text} [\${language}]\`),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<main className="mx-auto max-w-4xl px-6 py-20">
|
|
173
|
+
<p className="text-sm font-medium uppercase tracking-widest text-cyan-300">
|
|
174
|
+
Effect · TanStack Router · Tailwind · i18n
|
|
175
|
+
</p>
|
|
176
|
+
<h1 className="mt-4 text-5xl font-bold tracking-tight">{message}</h1>
|
|
177
|
+
<p className="mt-6 text-slate-300">
|
|
178
|
+
Edit <code>src/routes/page.tsx</code> to get started.
|
|
179
|
+
</p>
|
|
180
|
+
</main>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
`;
|
|
184
|
+
const ultramodernSandpackFiles = {
|
|
185
|
+
'/.browserslistrc': 'defaults\n',
|
|
186
|
+
'/.codesandbox/environment.json': '{\n "nodeVersion": "26"\n}\n',
|
|
187
|
+
'/.codesandbox/tasks.json': codeSandboxTasks,
|
|
188
|
+
'/modern.config.ts': modernConfig,
|
|
189
|
+
'/package.json': packageJson,
|
|
190
|
+
'/src/modern-app-env.d.ts': '/// <reference types="@modern-js/app-tools/types" />\n',
|
|
191
|
+
'/src/modern.runtime.ts': runtimeConfig,
|
|
192
|
+
'/src/routes/index.css': `@import 'tailwindcss' source(none);
|
|
193
|
+
@source '..';
|
|
194
|
+
|
|
195
|
+
html {
|
|
196
|
+
color-scheme: dark;
|
|
197
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
body {
|
|
201
|
+
margin: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
* {
|
|
205
|
+
box-sizing: border-box;
|
|
206
|
+
}
|
|
207
|
+
`,
|
|
208
|
+
'/src/routes/layout.tsx': layout,
|
|
209
|
+
'/src/routes/page.tsx': page,
|
|
210
|
+
'/tsconfig.json': `${JSON.stringify({
|
|
211
|
+
extends: '@modern-js/tsconfig/base',
|
|
212
|
+
compilerOptions: {
|
|
213
|
+
jsx: 'react-jsx',
|
|
214
|
+
noUncheckedIndexedAccess: true,
|
|
215
|
+
strict: true
|
|
216
|
+
},
|
|
217
|
+
include: [
|
|
218
|
+
'src',
|
|
219
|
+
'modern.config.ts'
|
|
220
|
+
]
|
|
221
|
+
}, null, 2)}\n`
|
|
222
|
+
};
|
|
223
|
+
export { ultramodernSandpackFiles };
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
const packageJson = `${JSON.stringify({
|
|
3
|
+
name: 'ultramodern-sandpack-app',
|
|
4
|
+
version: '0.1.0',
|
|
5
|
+
private: true,
|
|
6
|
+
type: 'module',
|
|
7
|
+
packageManager: 'pnpm@11.24.0',
|
|
8
|
+
scripts: {
|
|
9
|
+
dev: 'modern dev',
|
|
10
|
+
start: 'modern dev --host 0.0.0.0',
|
|
11
|
+
build: 'modern build'
|
|
12
|
+
},
|
|
13
|
+
engines: {
|
|
14
|
+
node: '>=26.7.0',
|
|
15
|
+
pnpm: '>=11.24.0'
|
|
16
|
+
},
|
|
17
|
+
dependencies: {
|
|
18
|
+
'@modern-js/plugin-i18n': 'npm:@bleedingdev/modern-js-plugin-i18n@latest',
|
|
19
|
+
'@modern-js/plugin-tanstack': 'npm:@bleedingdev/modern-js-plugin-tanstack@latest',
|
|
20
|
+
'@modern-js/runtime': 'npm:@bleedingdev/modern-js-runtime@latest',
|
|
21
|
+
effect: '4.0.0-rc.112',
|
|
22
|
+
i18next: '26.3.6',
|
|
23
|
+
react: '19.2.8',
|
|
24
|
+
'react-dom': '19.2.8'
|
|
25
|
+
},
|
|
26
|
+
devDependencies: {
|
|
27
|
+
'@modern-js/app-tools': 'npm:@bleedingdev/modern-js-app-tools@latest',
|
|
28
|
+
'@modern-js/tsconfig': 'npm:@bleedingdev/modern-js-tsconfig@latest',
|
|
29
|
+
'@rsbuild/plugin-tailwindcss': '2.0.3',
|
|
30
|
+
'@types/node': '^26.2.0',
|
|
31
|
+
'@types/react': '^19.2.18',
|
|
32
|
+
'@types/react-dom': '^19.2.4',
|
|
33
|
+
tailwindcss: '4.3.3',
|
|
34
|
+
typescript: '7.0.2'
|
|
35
|
+
}
|
|
36
|
+
}, null, 2)}\n`;
|
|
37
|
+
const codeSandboxTasks = `${JSON.stringify({
|
|
38
|
+
$schema: 'https://codesandbox.io/schemas/tasks.json',
|
|
39
|
+
setupTasks: [
|
|
40
|
+
{
|
|
41
|
+
name: 'Installing dependencies',
|
|
42
|
+
command: 'pnpm install'
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
tasks: {
|
|
46
|
+
start: {
|
|
47
|
+
name: 'UltraModern.js application',
|
|
48
|
+
command: 'pnpm start',
|
|
49
|
+
runAtStart: true,
|
|
50
|
+
preview: {
|
|
51
|
+
port: 8080,
|
|
52
|
+
prLink: 'direct'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}, null, 2)}\n`;
|
|
57
|
+
const modernConfig = `import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
58
|
+
import { i18nPlugin } from '@modern-js/plugin-i18n';
|
|
59
|
+
import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
|
|
60
|
+
import { pluginTailwindcss } from '@rsbuild/plugin-tailwindcss';
|
|
61
|
+
|
|
62
|
+
export default defineConfig({
|
|
63
|
+
builderPlugins: [pluginTailwindcss()],
|
|
64
|
+
output: {
|
|
65
|
+
disableTsChecker: false,
|
|
66
|
+
polyfill: 'off',
|
|
67
|
+
},
|
|
68
|
+
performance: {
|
|
69
|
+
buildCache: false,
|
|
70
|
+
},
|
|
71
|
+
plugins: [
|
|
72
|
+
appTools(),
|
|
73
|
+
tanstackRouterPlugin(),
|
|
74
|
+
i18nPlugin({
|
|
75
|
+
htmlLangAttr: true,
|
|
76
|
+
localeDetection: {
|
|
77
|
+
fallbackLanguage: 'en',
|
|
78
|
+
languages: ['en', 'cs'],
|
|
79
|
+
localePathRedirect: false,
|
|
80
|
+
},
|
|
81
|
+
reactI18next: false,
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
server: {
|
|
85
|
+
ssr: false,
|
|
86
|
+
},
|
|
87
|
+
source: {
|
|
88
|
+
alias: {
|
|
89
|
+
'@modern-js/plugin-i18n/runtime':
|
|
90
|
+
'@modern-js/plugin-i18n/runtime/no-react-i18next',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
`;
|
|
95
|
+
const runtimeConfig = `import { defineRuntimeConfig } from '@modern-js/runtime';
|
|
96
|
+
import { createInstance } from 'i18next';
|
|
97
|
+
|
|
98
|
+
const i18nInstance = createInstance();
|
|
99
|
+
|
|
100
|
+
export default defineRuntimeConfig({
|
|
101
|
+
i18n: {
|
|
102
|
+
i18nInstance,
|
|
103
|
+
initOptions: {
|
|
104
|
+
defaultNS: 'translation',
|
|
105
|
+
fallbackLng: 'en',
|
|
106
|
+
lng: 'en',
|
|
107
|
+
resources: {
|
|
108
|
+
en: {
|
|
109
|
+
translation: {
|
|
110
|
+
language: 'Language',
|
|
111
|
+
welcome: 'Build a fast, typed UltraModern.js application.',
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
cs: {
|
|
115
|
+
translation: {
|
|
116
|
+
language: 'Jazyk',
|
|
117
|
+
welcome: 'Vytvořte rychlou a typově bezpečnou UltraModern.js aplikaci.',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
supportedLngs: ['en', 'cs'],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
router: {
|
|
125
|
+
framework: 'tanstack',
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
`;
|
|
129
|
+
const layout = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
130
|
+
import { Link, Outlet } from '@modern-js/plugin-tanstack/runtime';
|
|
131
|
+
|
|
132
|
+
export default function Layout() {
|
|
133
|
+
const { changeLanguage, language, t } = useModernI18n();
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<div className="min-h-screen bg-slate-950 text-slate-100">
|
|
137
|
+
<header className="mx-auto flex max-w-4xl items-center justify-between p-6">
|
|
138
|
+
<Link className="font-semibold" prefetch="render" to="/">
|
|
139
|
+
UltraModern.js
|
|
140
|
+
</Link>
|
|
141
|
+
<label className="flex items-center gap-2 text-sm">
|
|
142
|
+
{t('language')}
|
|
143
|
+
<select
|
|
144
|
+
aria-label={t('language')}
|
|
145
|
+
className="rounded bg-slate-800 px-2 py-1"
|
|
146
|
+
onChange={event => void changeLanguage(event.currentTarget.value)}
|
|
147
|
+
value={language}
|
|
148
|
+
>
|
|
149
|
+
<option value="en">English</option>
|
|
150
|
+
<option value="cs">Čeština</option>
|
|
151
|
+
</select>
|
|
152
|
+
</label>
|
|
153
|
+
</header>
|
|
154
|
+
<Outlet />
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
const page = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
160
|
+
import { Effect, pipe } from 'effect';
|
|
161
|
+
import './index.css';
|
|
162
|
+
|
|
163
|
+
export default function HomePage() {
|
|
164
|
+
const { language, t } = useModernI18n();
|
|
165
|
+
const message = Effect.runSync(
|
|
166
|
+
pipe(
|
|
167
|
+
Effect.succeed(t('welcome')),
|
|
168
|
+
Effect.map(text => \`\${text} [\${language}]\`),
|
|
169
|
+
),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<main className="mx-auto max-w-4xl px-6 py-20">
|
|
174
|
+
<p className="text-sm font-medium uppercase tracking-widest text-cyan-300">
|
|
175
|
+
Effect · TanStack Router · Tailwind · i18n
|
|
176
|
+
</p>
|
|
177
|
+
<h1 className="mt-4 text-5xl font-bold tracking-tight">{message}</h1>
|
|
178
|
+
<p className="mt-6 text-slate-300">
|
|
179
|
+
Edit <code>src/routes/page.tsx</code> to get started.
|
|
180
|
+
</p>
|
|
181
|
+
</main>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
`;
|
|
185
|
+
const ultramodernSandpackFiles = {
|
|
186
|
+
'/.browserslistrc': 'defaults\n',
|
|
187
|
+
'/.codesandbox/environment.json': '{\n "nodeVersion": "26"\n}\n',
|
|
188
|
+
'/.codesandbox/tasks.json': codeSandboxTasks,
|
|
189
|
+
'/modern.config.ts': modernConfig,
|
|
190
|
+
'/package.json': packageJson,
|
|
191
|
+
'/src/modern-app-env.d.ts': '/// <reference types="@modern-js/app-tools/types" />\n',
|
|
192
|
+
'/src/modern.runtime.ts': runtimeConfig,
|
|
193
|
+
'/src/routes/index.css': `@import 'tailwindcss' source(none);
|
|
194
|
+
@source '..';
|
|
195
|
+
|
|
196
|
+
html {
|
|
197
|
+
color-scheme: dark;
|
|
198
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
body {
|
|
202
|
+
margin: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
* {
|
|
206
|
+
box-sizing: border-box;
|
|
207
|
+
}
|
|
208
|
+
`,
|
|
209
|
+
'/src/routes/layout.tsx': layout,
|
|
210
|
+
'/src/routes/page.tsx': page,
|
|
211
|
+
'/tsconfig.json': `${JSON.stringify({
|
|
212
|
+
extends: '@modern-js/tsconfig/base',
|
|
213
|
+
compilerOptions: {
|
|
214
|
+
jsx: 'react-jsx',
|
|
215
|
+
noUncheckedIndexedAccess: true,
|
|
216
|
+
strict: true
|
|
217
|
+
},
|
|
218
|
+
include: [
|
|
219
|
+
'src',
|
|
220
|
+
'modern.config.ts'
|
|
221
|
+
]
|
|
222
|
+
}, null, 2)}\n`
|
|
223
|
+
};
|
|
224
|
+
export { ultramodernSandpackFiles };
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bleedingdev/modern-js-ultramodern-sandpack-profile",
|
|
3
|
+
"description": "Fork-owned executable Sandpack profile for UltraModern.js applications.",
|
|
4
|
+
"homepage": "https://github.com/BleedingDev/ultramodern.js#readme",
|
|
5
|
+
"bugs": {
|
|
6
|
+
"url": "https://github.com/BleedingDev/ultramodern.js/issues"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/BleedingDev/ultramodern.js.git",
|
|
11
|
+
"directory": "packages/toolkit/ultramodern-sandpack-profile"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"version": "3.8.3-ultramodern.2",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"types": "./dist/types/index.d.ts",
|
|
17
|
+
"main": "./dist/esm/index.js",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/types/index.d.ts",
|
|
21
|
+
"import": "./dist/esm/index.js",
|
|
22
|
+
"default": "./dist/esm/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"typesVersions": {
|
|
26
|
+
"*": {
|
|
27
|
+
".": [
|
|
28
|
+
"./dist/types/index.d.ts",
|
|
29
|
+
"./src/index.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=26.7.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@rslib/core": "0.23.2",
|
|
38
|
+
"@types/node": "^26.2.0",
|
|
39
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2"
|
|
40
|
+
},
|
|
41
|
+
"sideEffects": false,
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "rslib build",
|
|
47
|
+
"dev": "rslib build --watch",
|
|
48
|
+
"test": "node --experimental-strip-types --test tests/*.test.ts",
|
|
49
|
+
"test:build-smoke": "node --experimental-strip-types --test tests/*.smoke.ts"
|
|
50
|
+
}
|
|
51
|
+
}
|
package/rslib.config.mts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
export type UltramodernSandpackFiles = Readonly<Record<`/${string}`, string>>;
|
|
2
|
+
|
|
3
|
+
const packageJson = `${JSON.stringify(
|
|
4
|
+
{
|
|
5
|
+
name: 'ultramodern-sandpack-app',
|
|
6
|
+
version: '0.1.0',
|
|
7
|
+
private: true,
|
|
8
|
+
type: 'module',
|
|
9
|
+
packageManager: 'pnpm@11.24.0',
|
|
10
|
+
scripts: {
|
|
11
|
+
dev: 'modern dev',
|
|
12
|
+
start: 'modern dev --host 0.0.0.0',
|
|
13
|
+
build: 'modern build',
|
|
14
|
+
},
|
|
15
|
+
engines: {
|
|
16
|
+
node: '>=26.7.0',
|
|
17
|
+
pnpm: '>=11.24.0',
|
|
18
|
+
},
|
|
19
|
+
dependencies: {
|
|
20
|
+
'@modern-js/plugin-i18n': 'npm:@bleedingdev/modern-js-plugin-i18n@latest',
|
|
21
|
+
'@modern-js/plugin-tanstack':
|
|
22
|
+
'npm:@bleedingdev/modern-js-plugin-tanstack@latest',
|
|
23
|
+
'@modern-js/runtime': 'npm:@bleedingdev/modern-js-runtime@latest',
|
|
24
|
+
effect: '4.0.0-rc.112',
|
|
25
|
+
i18next: '26.3.6',
|
|
26
|
+
react: '19.2.8',
|
|
27
|
+
'react-dom': '19.2.8',
|
|
28
|
+
},
|
|
29
|
+
devDependencies: {
|
|
30
|
+
'@modern-js/app-tools': 'npm:@bleedingdev/modern-js-app-tools@latest',
|
|
31
|
+
'@modern-js/tsconfig': 'npm:@bleedingdev/modern-js-tsconfig@latest',
|
|
32
|
+
'@rsbuild/plugin-tailwindcss': '2.0.3',
|
|
33
|
+
'@types/node': '^26.2.0',
|
|
34
|
+
'@types/react': '^19.2.18',
|
|
35
|
+
'@types/react-dom': '^19.2.4',
|
|
36
|
+
tailwindcss: '4.3.3',
|
|
37
|
+
typescript: '7.0.2',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
null,
|
|
41
|
+
2,
|
|
42
|
+
)}\n`;
|
|
43
|
+
|
|
44
|
+
const codeSandboxTasks = `${JSON.stringify(
|
|
45
|
+
{
|
|
46
|
+
$schema: 'https://codesandbox.io/schemas/tasks.json',
|
|
47
|
+
setupTasks: [
|
|
48
|
+
{
|
|
49
|
+
name: 'Installing dependencies',
|
|
50
|
+
command: 'pnpm install',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
tasks: {
|
|
54
|
+
start: {
|
|
55
|
+
name: 'UltraModern.js application',
|
|
56
|
+
command: 'pnpm start',
|
|
57
|
+
runAtStart: true,
|
|
58
|
+
preview: {
|
|
59
|
+
port: 8080,
|
|
60
|
+
prLink: 'direct',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
null,
|
|
66
|
+
2,
|
|
67
|
+
)}\n`;
|
|
68
|
+
|
|
69
|
+
const modernConfig = `import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
70
|
+
import { i18nPlugin } from '@modern-js/plugin-i18n';
|
|
71
|
+
import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
|
|
72
|
+
import { pluginTailwindcss } from '@rsbuild/plugin-tailwindcss';
|
|
73
|
+
|
|
74
|
+
export default defineConfig({
|
|
75
|
+
builderPlugins: [pluginTailwindcss()],
|
|
76
|
+
output: {
|
|
77
|
+
disableTsChecker: false,
|
|
78
|
+
polyfill: 'off',
|
|
79
|
+
},
|
|
80
|
+
performance: {
|
|
81
|
+
buildCache: false,
|
|
82
|
+
},
|
|
83
|
+
plugins: [
|
|
84
|
+
appTools(),
|
|
85
|
+
tanstackRouterPlugin(),
|
|
86
|
+
i18nPlugin({
|
|
87
|
+
htmlLangAttr: true,
|
|
88
|
+
localeDetection: {
|
|
89
|
+
fallbackLanguage: 'en',
|
|
90
|
+
languages: ['en', 'cs'],
|
|
91
|
+
localePathRedirect: false,
|
|
92
|
+
},
|
|
93
|
+
reactI18next: false,
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
server: {
|
|
97
|
+
ssr: false,
|
|
98
|
+
},
|
|
99
|
+
source: {
|
|
100
|
+
alias: {
|
|
101
|
+
'@modern-js/plugin-i18n/runtime':
|
|
102
|
+
'@modern-js/plugin-i18n/runtime/no-react-i18next',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
const runtimeConfig = `import { defineRuntimeConfig } from '@modern-js/runtime';
|
|
109
|
+
import { createInstance } from 'i18next';
|
|
110
|
+
|
|
111
|
+
const i18nInstance = createInstance();
|
|
112
|
+
|
|
113
|
+
export default defineRuntimeConfig({
|
|
114
|
+
i18n: {
|
|
115
|
+
i18nInstance,
|
|
116
|
+
initOptions: {
|
|
117
|
+
defaultNS: 'translation',
|
|
118
|
+
fallbackLng: 'en',
|
|
119
|
+
lng: 'en',
|
|
120
|
+
resources: {
|
|
121
|
+
en: {
|
|
122
|
+
translation: {
|
|
123
|
+
language: 'Language',
|
|
124
|
+
welcome: 'Build a fast, typed UltraModern.js application.',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
cs: {
|
|
128
|
+
translation: {
|
|
129
|
+
language: 'Jazyk',
|
|
130
|
+
welcome: 'Vytvořte rychlou a typově bezpečnou UltraModern.js aplikaci.',
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
supportedLngs: ['en', 'cs'],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
router: {
|
|
138
|
+
framework: 'tanstack',
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
`;
|
|
142
|
+
|
|
143
|
+
const layout = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
144
|
+
import { Link, Outlet } from '@modern-js/plugin-tanstack/runtime';
|
|
145
|
+
|
|
146
|
+
export default function Layout() {
|
|
147
|
+
const { changeLanguage, language, t } = useModernI18n();
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<div className="min-h-screen bg-slate-950 text-slate-100">
|
|
151
|
+
<header className="mx-auto flex max-w-4xl items-center justify-between p-6">
|
|
152
|
+
<Link className="font-semibold" prefetch="render" to="/">
|
|
153
|
+
UltraModern.js
|
|
154
|
+
</Link>
|
|
155
|
+
<label className="flex items-center gap-2 text-sm">
|
|
156
|
+
{t('language')}
|
|
157
|
+
<select
|
|
158
|
+
aria-label={t('language')}
|
|
159
|
+
className="rounded bg-slate-800 px-2 py-1"
|
|
160
|
+
onChange={event => void changeLanguage(event.currentTarget.value)}
|
|
161
|
+
value={language}
|
|
162
|
+
>
|
|
163
|
+
<option value="en">English</option>
|
|
164
|
+
<option value="cs">Čeština</option>
|
|
165
|
+
</select>
|
|
166
|
+
</label>
|
|
167
|
+
</header>
|
|
168
|
+
<Outlet />
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
const page = `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
175
|
+
import { Effect, pipe } from 'effect';
|
|
176
|
+
import './index.css';
|
|
177
|
+
|
|
178
|
+
export default function HomePage() {
|
|
179
|
+
const { language, t } = useModernI18n();
|
|
180
|
+
const message = Effect.runSync(
|
|
181
|
+
pipe(
|
|
182
|
+
Effect.succeed(t('welcome')),
|
|
183
|
+
Effect.map(text => \`\${text} [\${language}]\`),
|
|
184
|
+
),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<main className="mx-auto max-w-4xl px-6 py-20">
|
|
189
|
+
<p className="text-sm font-medium uppercase tracking-widest text-cyan-300">
|
|
190
|
+
Effect · TanStack Router · Tailwind · i18n
|
|
191
|
+
</p>
|
|
192
|
+
<h1 className="mt-4 text-5xl font-bold tracking-tight">{message}</h1>
|
|
193
|
+
<p className="mt-6 text-slate-300">
|
|
194
|
+
Edit <code>src/routes/page.tsx</code> to get started.
|
|
195
|
+
</p>
|
|
196
|
+
</main>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
`;
|
|
200
|
+
|
|
201
|
+
export const ultramodernSandpackFiles: UltramodernSandpackFiles = {
|
|
202
|
+
'/.browserslistrc': 'defaults\n',
|
|
203
|
+
'/.codesandbox/environment.json': '{\n "nodeVersion": "26"\n}\n',
|
|
204
|
+
'/.codesandbox/tasks.json': codeSandboxTasks,
|
|
205
|
+
'/modern.config.ts': modernConfig,
|
|
206
|
+
'/package.json': packageJson,
|
|
207
|
+
'/src/modern-app-env.d.ts':
|
|
208
|
+
'/// <reference types="@modern-js/app-tools/types" />\n',
|
|
209
|
+
'/src/modern.runtime.ts': runtimeConfig,
|
|
210
|
+
'/src/routes/index.css': `@import 'tailwindcss' source(none);
|
|
211
|
+
@source '..';
|
|
212
|
+
|
|
213
|
+
html {
|
|
214
|
+
color-scheme: dark;
|
|
215
|
+
font-family: Inter, ui-sans-serif, system-ui, sans-serif;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
body {
|
|
219
|
+
margin: 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
* {
|
|
223
|
+
box-sizing: border-box;
|
|
224
|
+
}
|
|
225
|
+
`,
|
|
226
|
+
'/src/routes/layout.tsx': layout,
|
|
227
|
+
'/src/routes/page.tsx': page,
|
|
228
|
+
'/tsconfig.json': `${JSON.stringify(
|
|
229
|
+
{
|
|
230
|
+
extends: '@modern-js/tsconfig/base',
|
|
231
|
+
compilerOptions: {
|
|
232
|
+
jsx: 'react-jsx',
|
|
233
|
+
noUncheckedIndexedAccess: true,
|
|
234
|
+
strict: true,
|
|
235
|
+
},
|
|
236
|
+
include: ['src', 'modern.config.ts'],
|
|
237
|
+
},
|
|
238
|
+
null,
|
|
239
|
+
2,
|
|
240
|
+
)}\n`,
|
|
241
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import {
|
|
4
|
+
lstat,
|
|
5
|
+
mkdir,
|
|
6
|
+
mkdtemp,
|
|
7
|
+
readdir,
|
|
8
|
+
readFile,
|
|
9
|
+
rm,
|
|
10
|
+
symlink,
|
|
11
|
+
writeFile,
|
|
12
|
+
} from 'node:fs/promises';
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { after, test } from 'node:test';
|
|
16
|
+
import { ultramodernSandpackFiles } from '../src/index.ts';
|
|
17
|
+
|
|
18
|
+
const fixtureRoots: string[] = [];
|
|
19
|
+
const repositoryRoot = path.resolve(import.meta.dirname, '../../../..');
|
|
20
|
+
|
|
21
|
+
async function listFiles(root: string, directory = root): Promise<string[]> {
|
|
22
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
23
|
+
const files = await Promise.all(
|
|
24
|
+
entries.map(async entry => {
|
|
25
|
+
const absolutePath = path.join(directory, entry.name);
|
|
26
|
+
return entry.isDirectory()
|
|
27
|
+
? listFiles(root, absolutePath)
|
|
28
|
+
: [path.relative(root, absolutePath)];
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
return files.flat();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function materializeBuildFixture() {
|
|
35
|
+
const root = await mkdtemp(
|
|
36
|
+
path.join(os.tmpdir(), 'ultramodern-sandpack-build-'),
|
|
37
|
+
);
|
|
38
|
+
fixtureRoots.push(root);
|
|
39
|
+
|
|
40
|
+
for (const [relativePath, source] of Object.entries(
|
|
41
|
+
ultramodernSandpackFiles,
|
|
42
|
+
)) {
|
|
43
|
+
const outputPath = path.join(root, relativePath.replace(/^\//u, ''));
|
|
44
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
45
|
+
await writeFile(outputPath, source, 'utf8');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
await symlink(
|
|
49
|
+
path.join(repositoryRoot, 'node_modules'),
|
|
50
|
+
path.join(root, 'node_modules'),
|
|
51
|
+
);
|
|
52
|
+
return root;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
after(async () => {
|
|
56
|
+
await Promise.all(
|
|
57
|
+
fixtureRoots.map(root => rm(root, { force: true, recursive: true })),
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('the materialized profile builds through the real Modern.js CLI', async () => {
|
|
62
|
+
const fixtureRoot = await materializeBuildFixture();
|
|
63
|
+
const modernCli = path.join(
|
|
64
|
+
repositoryRoot,
|
|
65
|
+
'packages/solutions/app-tools/bin/modern.js',
|
|
66
|
+
);
|
|
67
|
+
const cliMetadata = await lstat(modernCli);
|
|
68
|
+
assert.equal(cliMetadata.isFile(), true);
|
|
69
|
+
|
|
70
|
+
const result = spawnSync(process.execPath, [modernCli, 'build'], {
|
|
71
|
+
cwd: fixtureRoot,
|
|
72
|
+
encoding: 'utf8',
|
|
73
|
+
env: {
|
|
74
|
+
...process.env,
|
|
75
|
+
FORCE_COLOR: '0',
|
|
76
|
+
NO_COLOR: '1',
|
|
77
|
+
},
|
|
78
|
+
timeout: 180_000,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
assert.equal(
|
|
82
|
+
result.status,
|
|
83
|
+
0,
|
|
84
|
+
`modern build failed\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const distRoot = path.join(fixtureRoot, 'dist');
|
|
88
|
+
const emittedFiles = await listFiles(distRoot);
|
|
89
|
+
const htmlPath = emittedFiles.find(file => file.endsWith('.html'));
|
|
90
|
+
assert.ok(htmlPath, `build emitted no HTML: ${emittedFiles.join(', ')}`);
|
|
91
|
+
assert.ok(
|
|
92
|
+
emittedFiles.some(file => /\.(?:js|mjs)$/u.test(file)),
|
|
93
|
+
`build emitted no JavaScript: ${emittedFiles.join(', ')}`,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const html = await readFile(path.join(distRoot, htmlPath), 'utf8');
|
|
97
|
+
assert.match(html, /<script\b/u);
|
|
98
|
+
assert.match(html, /<html\b[^>]*\blang=/u);
|
|
99
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { after, test } from 'node:test';
|
|
6
|
+
import { ultramodernSandpackFiles } from '../src/index.ts';
|
|
7
|
+
|
|
8
|
+
const materializedRoots: string[] = [];
|
|
9
|
+
|
|
10
|
+
async function materializeProfile() {
|
|
11
|
+
const root = await mkdtemp(
|
|
12
|
+
path.join(os.tmpdir(), 'ultramodern-sandpack-profile-'),
|
|
13
|
+
);
|
|
14
|
+
materializedRoots.push(root);
|
|
15
|
+
|
|
16
|
+
for (const [relativePath, source] of Object.entries(
|
|
17
|
+
ultramodernSandpackFiles,
|
|
18
|
+
)) {
|
|
19
|
+
const outputPath = path.join(root, relativePath.replace(/^\//u, ''));
|
|
20
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
21
|
+
await writeFile(outputPath, source, 'utf8');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return root;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
after(async () => {
|
|
28
|
+
await Promise.all(
|
|
29
|
+
materializedRoots.map(root => rm(root, { force: true, recursive: true })),
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('materializes an executable UltraModern single-app profile', async () => {
|
|
34
|
+
const root = await materializeProfile();
|
|
35
|
+
const manifest = JSON.parse(
|
|
36
|
+
await readFile(path.join(root, 'package.json'), 'utf8'),
|
|
37
|
+
);
|
|
38
|
+
const tasks = JSON.parse(
|
|
39
|
+
await readFile(path.join(root, '.codesandbox/tasks.json'), 'utf8'),
|
|
40
|
+
);
|
|
41
|
+
const environment = JSON.parse(
|
|
42
|
+
await readFile(path.join(root, '.codesandbox/environment.json'), 'utf8'),
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
assert.equal(manifest.engines.node, '>=26.7.0');
|
|
46
|
+
assert.equal(manifest.packageManager, 'pnpm@11.24.0');
|
|
47
|
+
assert.equal(manifest.scripts.start, 'modern dev --host 0.0.0.0');
|
|
48
|
+
assert.equal(manifest.scripts.build, 'modern build');
|
|
49
|
+
assert.equal(tasks.tasks.start.command, 'pnpm start');
|
|
50
|
+
assert.equal(environment.nodeVersion, '26');
|
|
51
|
+
|
|
52
|
+
for (const packageName of [
|
|
53
|
+
'@modern-js/app-tools',
|
|
54
|
+
'@modern-js/plugin-i18n',
|
|
55
|
+
'@modern-js/plugin-tanstack',
|
|
56
|
+
'@modern-js/runtime',
|
|
57
|
+
]) {
|
|
58
|
+
const selector =
|
|
59
|
+
manifest.dependencies?.[packageName] ??
|
|
60
|
+
manifest.devDependencies?.[packageName];
|
|
61
|
+
assert.match(
|
|
62
|
+
selector,
|
|
63
|
+
new RegExp(
|
|
64
|
+
`^npm:@bleedingdev/modern-js-${packageName.split('/').at(-1)}@`,
|
|
65
|
+
'u',
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
assert.equal(manifest.dependencies.effect, '4.0.0-rc.112');
|
|
71
|
+
assert.equal(manifest.dependencies.i18next, '26.3.6');
|
|
72
|
+
assert.equal(manifest.devDependencies.tailwindcss, '4.3.3');
|
|
73
|
+
assert.equal(
|
|
74
|
+
manifest.devDependencies['@rsbuild/plugin-tailwindcss'],
|
|
75
|
+
'2.0.3',
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('declares every UltraModern capability in executable entrypoints', async () => {
|
|
80
|
+
const root = await materializeProfile();
|
|
81
|
+
const config = await readFile(path.join(root, 'modern.config.ts'), 'utf8');
|
|
82
|
+
const runtime = await readFile(
|
|
83
|
+
path.join(root, 'src/modern.runtime.ts'),
|
|
84
|
+
'utf8',
|
|
85
|
+
);
|
|
86
|
+
const layout = await readFile(
|
|
87
|
+
path.join(root, 'src/routes/layout.tsx'),
|
|
88
|
+
'utf8',
|
|
89
|
+
);
|
|
90
|
+
const page = await readFile(path.join(root, 'src/routes/page.tsx'), 'utf8');
|
|
91
|
+
const styles = await readFile(
|
|
92
|
+
path.join(root, 'src/routes/index.css'),
|
|
93
|
+
'utf8',
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
assert.match(config, /tanstackRouterPlugin\(\)/u);
|
|
97
|
+
assert.match(config, /i18nPlugin\(/u);
|
|
98
|
+
assert.match(config, /pluginTailwindcss\(\)/u);
|
|
99
|
+
assert.match(runtime, /framework: 'tanstack'/u);
|
|
100
|
+
assert.match(runtime, /supportedLngs: \['en', 'cs'\]/u);
|
|
101
|
+
assert.match(layout, /@modern-js\/plugin-tanstack\/runtime/u);
|
|
102
|
+
assert.match(layout, /prefetch="render"/u);
|
|
103
|
+
assert.match(page, /Effect\.runSync/u);
|
|
104
|
+
assert.match(page, /useModernI18n/u);
|
|
105
|
+
assert.match(styles, /@import 'tailwindcss'/u);
|
|
106
|
+
});
|