@unsetsoft/ryunix-presets 1.0.26-canary.13 → 1.0.26-canary.16

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@unsetsoft/ryunix-presets",
3
3
  "description": "Package with presets for different development environments.",
4
- "version": "1.0.26-canary.13",
4
+ "version": "1.0.26-canary.16",
5
5
  "author": "Neyunse",
6
6
  "type": "module",
7
7
  "repository": "https://github.com/UnSetSoft/Ryunixjs",
@@ -56,16 +56,25 @@ const StartServer = async (cliSettings) => {
56
56
  cleanCacheDir(cacheDir)
57
57
  }
58
58
 
59
- webpackConfig.mode = mode ? 'production' : 'development'
59
+ const clientConfig = Array.isArray(webpackConfig) ? webpackConfig.find(c => c.name === 'client') || webpackConfig[0] : webpackConfig
60
+
61
+ if (Array.isArray(webpackConfig)) {
62
+ webpackConfig.forEach(c => c.mode = mode ? 'production' : 'development')
63
+ } else {
64
+ webpackConfig.mode = mode ? 'production' : 'development'
65
+ }
66
+
60
67
  const compiler = Webpack(webpackConfig)
61
- let port = webpackConfig.devServer.port || 3000
68
+ let port = clientConfig.devServer?.port || 3000
62
69
 
63
70
  // Encontrar un puerto disponible
64
71
  port = await findAvailablePort(port)
65
72
 
66
73
  // Modificamos el puerto en la configuración
67
- webpackConfig.devServer.port = port
68
- const devServerOptions = { ...webpackConfig.devServer, ...cliSettings }
74
+ if (clientConfig.devServer) {
75
+ clientConfig.devServer.port = port
76
+ }
77
+ const devServerOptions = { ...(clientConfig.devServer || {}), ...cliSettings }
69
78
  const server = new WebpackDevServer(devServerOptions, compiler)
70
79
 
71
80
  const devMode = Boolean(!mode)
@@ -1,4 +1,4 @@
1
- #! /usr/bin/env node
1
+ #! /usr/bin/env node
2
2
  import yargs from 'yargs'
3
3
  import { hideBin } from 'yargs/helpers'
4
4
  import { StartDevServer } from './dev.server.mjs'
@@ -13,12 +13,7 @@
13
13
  <title><%= htmlWebpackPlugin.options.title %></title>
14
14
  </head>
15
15
  <body>
16
- <noscript style="background: #f4f47f;color: black;padding: 10px;">
17
- <div style="display: flex;justify-content: center;align-items: center;">
18
- <p><b>Warning:</b> JavaScript is not enabled. Some features may not work.
19
- </p>
20
- </div>
21
- </noscript>
16
+ <%= htmlWebpackPlugin.options.ssrScript %>
22
17
  <div id="__ryunix"></div>
23
18
  </body>
24
19
  </html>
@@ -660,4 +660,5 @@ export {
660
660
  generateMetaTags,
661
661
  prerenderRoute,
662
662
  buildSSG,
663
+ importEsmFile,
663
664
  }
@@ -0,0 +1,98 @@
1
+ import fs from 'fs'
2
+ import { prerenderRoute } from './ssg.mjs'
3
+ import { resolveApp } from './index.mjs'
4
+
5
+ export async function renderDevRoute(req, res, devServer, dir, config) {
6
+ // We only care about GET requests for HTML documents
7
+ if (req.method !== 'GET' || !req.headers.accept?.includes('text/html')) {
8
+ return false
9
+ }
10
+
11
+ // Find client compiler to read index.html from its memory file system
12
+ const clientCompiler = devServer.compiler.compilers
13
+ ? devServer.compiler.compilers.find((c) => c.name === 'client')
14
+ : devServer.compiler
15
+
16
+ if (!clientCompiler) return false
17
+
18
+ const outputFs = clientCompiler.outputFileSystem
19
+ const buildDir = config.webpack.output.buildDirectory
20
+ const indexPath = resolveApp(dir, `${buildDir}/static/index.html`)
21
+
22
+ let template
23
+ try {
24
+ template = outputFs.readFileSync(indexPath, 'utf-8')
25
+ } catch (err) {
26
+ // index.html not generated yet, let the dev server handle default logic
27
+ return false
28
+ }
29
+
30
+ let AppRouterApp = null
31
+ let ryunixRenderToString = null
32
+ let ryunixCreateElement = null
33
+
34
+ try {
35
+ const serverBundlePath = resolveApp(dir, `${buildDir}/server/app-router-server.bundle.mjs`)
36
+ if (fs.existsSync(serverBundlePath)) {
37
+ if (typeof global.window === 'undefined') {
38
+ global.window = { location: { pathname: req.url } }
39
+ }
40
+ if (typeof global.document === 'undefined') {
41
+ global.document = { querySelector: () => null, getElementById: () => null }
42
+ }
43
+
44
+ const serverModule = await import(`file://${serverBundlePath}?update=${Date.now()}`)
45
+ AppRouterApp = serverModule.default?.default || serverModule.default
46
+
47
+ const ryunixCore = await import('@unsetsoft/ryunixjs')
48
+ const Ryunix = ryunixCore.default || ryunixCore
49
+ global.Ryunix = Ryunix
50
+ ryunixRenderToString = Ryunix.renderToString
51
+ ryunixCreateElement = Ryunix.createElement
52
+ }
53
+ } catch (e) {
54
+ console.warn(`[Ryunix SSR Dev] Failed to load server bundle: ${e.message}`)
55
+ return false // fallback to SPA
56
+ }
57
+
58
+ let renderedString = ''
59
+ if (AppRouterApp && ryunixRenderToString && ryunixCreateElement) {
60
+ global.window = { location: { pathname: req.url } }
61
+ try {
62
+ const element = ryunixCreateElement(AppRouterApp)
63
+ renderedString = ryunixRenderToString(element)
64
+ } catch (err) {
65
+ console.error(`[Ryunix SSR Dev] Render error:`, err)
66
+ }
67
+ }
68
+
69
+ // Generic mock route for prerenderRoute (to inject metadata)
70
+ const mockRoute = { path: req.url, meta: {} }
71
+
72
+ try {
73
+ let html = await prerenderRoute(mockRoute, template, config, renderedString)
74
+
75
+ // In dev mode with SSR, MiniCssExtractPlugin outputs CSS to the virtual filesystem.
76
+ // We need to inject <link> tags for them so there is no FOUC.
77
+ try {
78
+ const cssDir = resolveApp(dir, `${buildDir}/static/css`)
79
+ if (outputFs.existsSync(cssDir)) {
80
+ const cssFiles = outputFs.readdirSync(cssDir).filter(f => f.endsWith('.css'))
81
+ const styleLinks = cssFiles.map(f => `<link rel="stylesheet" href="/css/${f}" />`).join('\n')
82
+
83
+ if (styleLinks) {
84
+ html = html.replace('</head>', `${styleLinks}\n</head>`)
85
+ }
86
+ }
87
+ } catch (e) {
88
+ // Ignore errors reading CSS directory
89
+ }
90
+
91
+ res.setHeader('Content-Type', 'text/html; charset=utf-8')
92
+ res.end(html)
93
+ return true
94
+ } catch (err) {
95
+ console.error(`[Ryunix SSR Dev] Final render error:`, err)
96
+ return false
97
+ }
98
+ }
@@ -23,6 +23,7 @@ import RyunixRoutesPlugin from './utils/ssgPlugin.mjs'
23
23
  import AppRouterPlugin from './utils/appRouterPlugin.mjs'
24
24
  import ApiRouterPlugin from './utils/ApiRouterPlugin.mjs'
25
25
  import { handleApiRequest } from './utils/apiHandler.mjs'
26
+ import { renderDevRoute } from './utils/ssrDevHandler.mjs'
26
27
  import remarkGfm from 'remark-gfm'
27
28
  import remarkFrontmatter from 'remark-frontmatter'
28
29
  import remarkMdxFrontmatter from 'remark-mdx-frontmatter'
@@ -121,17 +122,17 @@ const sharedWebpackConfig = {
121
122
  minimize: config.webpack.production === true,
122
123
  minimizer: config.webpack.production
123
124
  ? [
124
- new TerserPlugin({
125
- parallel: true,
126
- terserOptions: {
127
- compress: {
128
- dead_code: true,
129
- passes: 2,
130
- },
125
+ new TerserPlugin({
126
+ parallel: true,
127
+ terserOptions: {
128
+ compress: {
129
+ dead_code: true,
130
+ passes: 2,
131
131
  },
132
- }),
133
- new CssMinimizerPlugin(),
134
- ]
132
+ },
133
+ }),
134
+ new CssMinimizerPlugin(),
135
+ ]
135
136
  : [],
136
137
  },
137
138
  cache: {
@@ -279,43 +280,61 @@ const getPlugins = (isServer = false) => [
279
280
  }),
280
281
  // Only inject HTML for the client build
281
282
  !isServer &&
282
- new HtmlWebpackPlugin({
283
- pageLang: config.static.seo.pageLang,
284
- title: config.static.seo.title,
285
- favicon: config.static.favicon
286
- ? join(dir, 'public', 'favicon.png')
287
- : false,
288
- meta: config.static.seo.meta,
289
- template: config.static.customTemplate
290
- ? join(dir, 'public', 'index.html')
291
- : join(__dirname, 'template', 'index.html'),
292
- info: {
293
- framework: 'Ryunix',
294
- version,
295
- mode: config.webpack.production ? 'production' : 'dev',
296
- },
297
- }),
283
+ new HtmlWebpackPlugin({
284
+ pageLang: config.static.seo.pageLang,
285
+ title: config.static.seo.title,
286
+ favicon: config.static.favicon
287
+ ? join(dir, 'public', 'favicon.png')
288
+ : false,
289
+ meta: config.static.seo.meta,
290
+ template: config.static.customTemplate
291
+ ? join(dir, 'public', 'index.html')
292
+ : join(__dirname, 'template', 'index.html'),
293
+ info: {
294
+ framework: 'Ryunix',
295
+ version,
296
+ mode: config.webpack.production ? 'production' : 'dev',
297
+ },
298
+ ssrScript: isServer ? `
299
+ <noscript
300
+ style="background: #f4f47f;color: black;padding: 10px;width: 100%;display: block;position: fixed;bottom: 0;z-index: 99;">
301
+ <div style="display: flex;justify-content: center;align-items: center;">
302
+ <p><b>Warning:</b> JavaScript is not enabled. Some features may not work.
303
+ </p>
304
+ </div>
305
+ </noscript>
306
+ ` : `
307
+ <noscript
308
+ style="background: #f57070ff;color: black;padding: 10px;width: 100%;display: block;position: fixed;bottom: 0;z-index: 99;">
309
+ <div style="display: flex;justify-content: center;align-items: center;">
310
+ <p><b>Error:</b> JavaScript is disabled. Please enable it to use this application.
311
+ </p>
312
+ </div>
313
+ </noscript>
314
+
315
+ `,
316
+ }),
298
317
  !isServer &&
299
- config.webpack.production &&
318
+ (config.webpack.production || config.experimental.ssr) &&
300
319
  new MiniCssExtractPlugin({
301
320
  filename: 'css/[name].[contenthash].css',
302
321
  }),
303
322
  !isServer &&
304
- new CopyWebpackPlugin({
305
- patterns: [
306
- {
307
- from: resolveApp(dir, 'public'),
308
- to: resolveApp(dir, `${config.webpack.output.buildDirectory}/static`),
309
- globOptions: {
310
- ignore: ['**/template.html', '**/index.html', '**/*.html', '**/favicon.png'],
311
- },
312
- filter: (resourcePath) => {
313
- try { return !resourcePath.toLowerCase().endsWith('.html') } catch { return true }
314
- },
315
- noErrorOnMissing: true,
323
+ new CopyWebpackPlugin({
324
+ patterns: [
325
+ {
326
+ from: resolveApp(dir, 'public'),
327
+ to: resolveApp(dir, `${config.webpack.output.buildDirectory}/static`),
328
+ globOptions: {
329
+ ignore: ['**/template.html', '**/index.html', '**/*.html', '**/favicon.png'],
316
330
  },
317
- ],
318
- }),
331
+ filter: (resourcePath) => {
332
+ try { return !resourcePath.toLowerCase().endsWith('.html') } catch { return true }
333
+ },
334
+ noErrorOnMissing: true,
335
+ },
336
+ ],
337
+ }),
319
338
  ...(!isServer ? config.webpack.plugins : []),
320
339
  ].filter(Boolean)
321
340
 
@@ -336,6 +355,11 @@ const clientConfig = {
336
355
  },
337
356
  devServer: {
338
357
  watchFiles: [resolveApp(dir, 'src/**/*'), resolveApp(dir, 'app/**/*')],
358
+ devMiddleware: {
359
+ writeToDisk: (filePath) => {
360
+ try { return filePath.includes('/server/') || filePath.includes('\\server\\') } catch { return false }
361
+ },
362
+ },
339
363
  hot: true,
340
364
  historyApiFallback: {
341
365
  index: '/',
@@ -367,6 +391,18 @@ const clientConfig = {
367
391
  }
368
392
  })
369
393
 
394
+ devServer.app.use(async (req, res, next) => {
395
+ try {
396
+ if (config.experimental.ssr) {
397
+ const handled = await renderDevRoute(req, res, devServer, dir, config)
398
+ if (handled) return
399
+ }
400
+ } catch (err) {
401
+ console.error('[Ryunix Dev SSR]', err)
402
+ }
403
+ next()
404
+ })
405
+
370
406
  return middlewares
371
407
  },
372
408
  },
@@ -379,7 +415,7 @@ const clientConfig = {
379
415
  test: /\.s[ac]ss|css$/i,
380
416
  exclude: /node_modules/,
381
417
  use: [
382
- config.webpack.production
418
+ (config.webpack.production || config.experimental.ssr)
383
419
  ? MiniCssExtractPlugin.loader
384
420
  : ryunixRequire.resolve('style-loader'),
385
421
  ryunixRequire.resolve('css-loader'),
@@ -487,7 +523,8 @@ const serverConfig = {
487
523
  ]
488
524
  }
489
525
 
490
- // Export dual compilers only in production if SSR or SSG prerender is enabled
491
- export default (config.webpack.production && (config.experimental.ssr || config.experimental.ssg?.prerender?.length > 0))
526
+ // Export dual compilers if SSR is enabled, or in production if SSG prerender is enabled
527
+ const enableServerDualCompiler = config.experimental.ssr || (config.webpack.production && config.experimental.ssg?.prerender?.length > 0);
528
+ export default enableServerDualCompiler
492
529
  ? [clientConfig, serverConfig]
493
530
  : clientConfig;