@ecomiq/storefront 2.0.3 → 2.0.7
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/README.md +10 -0
- package/bin/ecomiq.mjs +17 -5
- package/package.json +1 -1
- package/src/config.d.ts +2 -0
- package/src/config.mjs +6 -0
- package/src/vite-inline.mjs +85 -54
package/README.md
CHANGED
|
@@ -54,4 +54,14 @@ npx ecomiq clean
|
|
|
54
54
|
npx ecomiq dev
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
### Runtime de desarrollo
|
|
58
|
+
|
|
59
|
+
`ecomiq dev` usa **Node** por defecto. Para emular Workers en local:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
dev: { port: 3000, runtime: 'workerd' },
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`ecomiq build` / `deploy` siempre empaquetan para Cloudflare Workers.
|
|
66
|
+
|
|
57
67
|
Ver el monorepo [ecomiq-storefront](https://github.com/ecomiq/ecomiq-storefront) para la app de referencia y más documentación.
|
package/bin/ecomiq.mjs
CHANGED
|
@@ -16,7 +16,7 @@ import { resolve, dirname } from 'node:path'
|
|
|
16
16
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
17
17
|
import { generateApp, watchPages } from '../src/codegen.mjs'
|
|
18
18
|
import { parseConfig } from '../src/config.mjs'
|
|
19
|
-
import { createViteConfig } from '../src/vite-inline.mjs'
|
|
19
|
+
import { createViteConfig, resolveDevRuntime } from '../src/vite-inline.mjs'
|
|
20
20
|
|
|
21
21
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
22
22
|
const cwd = process.cwd()
|
|
@@ -80,9 +80,17 @@ export async function runCli(command = process.argv[2] ?? 'help') {
|
|
|
80
80
|
case 'dev': {
|
|
81
81
|
const config = await prepare()
|
|
82
82
|
const port = config.dev?.port ?? 3000
|
|
83
|
-
|
|
83
|
+
const runtime = resolveDevRuntime({ config })
|
|
84
84
|
const { createServer } = await import('vite')
|
|
85
|
-
const viteConfig = createViteConfig({
|
|
85
|
+
const viteConfig = createViteConfig({
|
|
86
|
+
appDir,
|
|
87
|
+
config,
|
|
88
|
+
projectRoot: cwd,
|
|
89
|
+
runtime,
|
|
90
|
+
})
|
|
91
|
+
banner(
|
|
92
|
+
`dev · ${config.name ?? 'tienda'} ${c.dim(`· runtime ${runtime}`)} ${c.dim('http://localhost:' + port)}`,
|
|
93
|
+
)
|
|
86
94
|
const server = await createServer({
|
|
87
95
|
...viteConfig,
|
|
88
96
|
server: {
|
|
@@ -115,7 +123,9 @@ export async function runCli(command = process.argv[2] ?? 'help') {
|
|
|
115
123
|
const config = await prepare()
|
|
116
124
|
banner(`build · Cloudflare Workers`)
|
|
117
125
|
const { createBuilder } = await import('vite')
|
|
118
|
-
const builder = await createBuilder(
|
|
126
|
+
const builder = await createBuilder(
|
|
127
|
+
createViteConfig({ appDir, config, projectRoot: cwd, runtime: 'workerd' }),
|
|
128
|
+
)
|
|
119
129
|
await builder.buildApp()
|
|
120
130
|
console.log(c.green('\n ✔ Build listo en .ecomiq/dist\n'))
|
|
121
131
|
break
|
|
@@ -124,7 +134,9 @@ export async function runCli(command = process.argv[2] ?? 'help') {
|
|
|
124
134
|
const config = await prepare()
|
|
125
135
|
banner(`deploy · Cloudflare Workers`)
|
|
126
136
|
const { createBuilder } = await import('vite')
|
|
127
|
-
const builder = await createBuilder(
|
|
137
|
+
const builder = await createBuilder(
|
|
138
|
+
createViteConfig({ appDir, config, projectRoot: cwd, runtime: 'workerd' }),
|
|
139
|
+
)
|
|
128
140
|
await builder.buildApp()
|
|
129
141
|
// @cloudflare/vite-plugin emite la config final del Worker junto al build
|
|
130
142
|
const built = resolve(appDir, 'dist', 'server', 'wrangler.json')
|
package/package.json
CHANGED
package/src/config.d.ts
CHANGED
package/src/config.mjs
CHANGED
|
@@ -124,6 +124,12 @@ const configSchema = z.object({
|
|
|
124
124
|
.object({
|
|
125
125
|
port: z.number().int().default(3000),
|
|
126
126
|
apiBaseUrl: z.string().url(),
|
|
127
|
+
/**
|
|
128
|
+
* Runtime SSR en `ecomiq dev`. Default: `node`.
|
|
129
|
+
* Usa `workerd` para emular Cloudflare Workers en local.
|
|
130
|
+
* `ecomiq build` / `deploy` siempre usan workerd.
|
|
131
|
+
*/
|
|
132
|
+
runtime: z.enum(['workerd', 'node']),
|
|
127
133
|
})
|
|
128
134
|
.partial()
|
|
129
135
|
.optional(),
|
package/src/vite-inline.mjs
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* No existe vite.config.ts en el proyecto del usuario ni en .ecomiq:
|
|
4
4
|
* los plugins se importan aquí (contexto del framework) y se pasan como
|
|
5
5
|
* instancias, así la resolución de módulos nunca depende del proyecto.
|
|
6
|
+
*
|
|
7
|
+
* Alineado con el ejemplo oficial TanStack Start + Cloudflare:
|
|
8
|
+
* https://github.com/TanStack/router/tree/main/examples/react/start-basic-cloudflare
|
|
6
9
|
*/
|
|
7
10
|
import { dirname, resolve } from 'node:path'
|
|
8
11
|
import { fileURLToPath } from 'node:url'
|
|
@@ -17,28 +20,6 @@ const postcssBrowserStub = fileURLToPath(
|
|
|
17
20
|
|
|
18
21
|
const frameworkRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
19
22
|
|
|
20
|
-
/** Packages que workerd debe ver como ESM (sin prebundle CJS con `require`). */
|
|
21
|
-
const SSR_NO_EXTERNAL = [
|
|
22
|
-
'@tanstack/react-start',
|
|
23
|
-
'@tanstack/react-router',
|
|
24
|
-
'@tanstack/react-query',
|
|
25
|
-
'@tanstack/router-core',
|
|
26
|
-
'@tanstack/history',
|
|
27
|
-
'@tanstack/react-store',
|
|
28
|
-
'@tanstack/start-server-core',
|
|
29
|
-
'@tanstack/start-client-core',
|
|
30
|
-
'@tanstack/start-storage-context',
|
|
31
|
-
'@ecomiq/storefront',
|
|
32
|
-
'@ecomiq/core',
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
const OPTIMIZE_EXCLUDE = [
|
|
36
|
-
'@tanstack/react-start',
|
|
37
|
-
'@tanstack/start-server-core',
|
|
38
|
-
'@tanstack/start-client-core',
|
|
39
|
-
'@tanstack/react-router',
|
|
40
|
-
]
|
|
41
|
-
|
|
42
23
|
function resolveSanitizeHtmlPostcss(source, importer) {
|
|
43
24
|
if (source !== 'postcss') return null
|
|
44
25
|
if (!importer?.includes('/sanitize-html/')) return null
|
|
@@ -74,7 +55,52 @@ function sanitizeHtmlClientBoundary() {
|
|
|
74
55
|
}
|
|
75
56
|
}
|
|
76
57
|
|
|
77
|
-
|
|
58
|
+
/**
|
|
59
|
+
* TanStack Start marca `@tanstack/react-router` como `resolve.external` fuera de
|
|
60
|
+
* su monorepo. Cloudflare Vite plugin no lo tolera y workerd acaba ejecutando
|
|
61
|
+
* CJS con `require` → "require is not defined".
|
|
62
|
+
*
|
|
63
|
+
* Solo aplica en runtime `workerd`. En `node`, React y otras deps CJS deben
|
|
64
|
+
* quedar external: `noExternal` las pasa por el module runner ESM de Vite y
|
|
65
|
+
* falla con "module is not defined".
|
|
66
|
+
* @see https://github.com/TanStack/router/issues/5291
|
|
67
|
+
*/
|
|
68
|
+
function bundleSsrDependenciesForWorkerd() {
|
|
69
|
+
return {
|
|
70
|
+
name: 'ecomiq:ssr-no-external',
|
|
71
|
+
configEnvironment(name) {
|
|
72
|
+
if (name !== 'ssr') return
|
|
73
|
+
return {
|
|
74
|
+
resolve: {
|
|
75
|
+
external: [],
|
|
76
|
+
noExternal: true,
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
configResolved(config) {
|
|
81
|
+
const ssr = config.environments?.ssr
|
|
82
|
+
if (ssr?.resolve) {
|
|
83
|
+
ssr.resolve.external = []
|
|
84
|
+
ssr.resolve.noExternal = true
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {{ appDir: string, config?: object, projectRoot?: string, runtime?: 'workerd' | 'node' }} opts
|
|
92
|
+
*/
|
|
93
|
+
export function resolveDevRuntime({ config, runtime } = {}) {
|
|
94
|
+
// Default: Node (compatible con npm/CodeSandbox). Opt-in a workerd con
|
|
95
|
+
// `dev.runtime: 'workerd'` (p. ej. monorepo local). build/deploy siempre
|
|
96
|
+
// fuerza workerd desde la CLI.
|
|
97
|
+
return runtime ?? config?.dev?.runtime ?? 'node'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {{ appDir: string, config?: object, projectRoot?: string, runtime?: 'workerd' | 'node' }} opts
|
|
102
|
+
*/
|
|
103
|
+
export function createViteConfig({ appDir, config, projectRoot, runtime }) {
|
|
78
104
|
const root = projectRoot ?? resolve(appDir, '..')
|
|
79
105
|
const allow = [
|
|
80
106
|
'..',
|
|
@@ -84,6 +110,37 @@ export function createViteConfig({ appDir, config, projectRoot }) {
|
|
|
84
110
|
resolve(root, 'node_modules'),
|
|
85
111
|
]
|
|
86
112
|
|
|
113
|
+
const resolvedRuntime = resolveDevRuntime({ config, runtime })
|
|
114
|
+
|
|
115
|
+
const plugins = [tailwindcss()]
|
|
116
|
+
|
|
117
|
+
if (resolvedRuntime === 'workerd') {
|
|
118
|
+
plugins.unshift(bundleSsrDependenciesForWorkerd())
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// workerd emula Cloudflare Workers (opt-in en `ecomiq dev`).
|
|
122
|
+
// Default es Node; build/deploy siempre usan workerd.
|
|
123
|
+
if (resolvedRuntime === 'workerd') {
|
|
124
|
+
plugins.push(
|
|
125
|
+
cloudflare({
|
|
126
|
+
configPath: resolve(appDir, 'wrangler.jsonc'),
|
|
127
|
+
viteEnvironment: { name: 'ssr' },
|
|
128
|
+
}),
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
plugins.push(
|
|
133
|
+
tanstackStart({
|
|
134
|
+
srcDirectory: 'src',
|
|
135
|
+
router: {
|
|
136
|
+
routesDirectory: 'routes',
|
|
137
|
+
generatedRouteTree: 'routeTree.gen.ts',
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
sanitizeHtmlClientBoundary(),
|
|
141
|
+
viteReact(),
|
|
142
|
+
)
|
|
143
|
+
|
|
87
144
|
return {
|
|
88
145
|
root: appDir,
|
|
89
146
|
configFile: false,
|
|
@@ -97,35 +154,12 @@ export function createViteConfig({ appDir, config, projectRoot }) {
|
|
|
97
154
|
'@tanstack/react-query',
|
|
98
155
|
],
|
|
99
156
|
},
|
|
100
|
-
|
|
101
|
-
// mantiene ESM. No usar optimizeDeps.include: el prebundle mete `require`
|
|
102
|
-
// y workerd (ESM) falla con "require is not defined".
|
|
103
|
-
ssr: {
|
|
104
|
-
noExternal: [...SSR_NO_EXTERNAL],
|
|
105
|
-
},
|
|
106
|
-
optimizeDeps: {
|
|
107
|
-
exclude: [...OPTIMIZE_EXCLUDE],
|
|
108
|
-
},
|
|
109
|
-
plugins: [
|
|
110
|
-
tailwindcss(),
|
|
111
|
-
// Emula el runtime de Workers en dev y empaqueta para Cloudflare en build.
|
|
112
|
-
cloudflare({
|
|
113
|
-
configPath: resolve(appDir, 'wrangler.jsonc'),
|
|
114
|
-
viteEnvironment: { name: 'ssr' },
|
|
115
|
-
}),
|
|
116
|
-
tanstackStart({
|
|
117
|
-
srcDirectory: 'src',
|
|
118
|
-
router: {
|
|
119
|
-
routesDirectory: 'routes',
|
|
120
|
-
generatedRouteTree: 'routeTree.gen.ts',
|
|
121
|
-
},
|
|
122
|
-
}),
|
|
123
|
-
sanitizeHtmlClientBoundary(),
|
|
124
|
-
viteReact(),
|
|
125
|
-
],
|
|
157
|
+
plugins,
|
|
126
158
|
build: {
|
|
127
|
-
// Un solo CSS; nombre estable → SSR y client apuntan al mismo asset en Workers.
|
|
128
159
|
cssCodeSplit: false,
|
|
160
|
+
commonjsOptions: {
|
|
161
|
+
transformMixedEsModules: true,
|
|
162
|
+
},
|
|
129
163
|
rollupOptions: {
|
|
130
164
|
output: {
|
|
131
165
|
assetFileNames: (assetInfo) => {
|
|
@@ -137,10 +171,7 @@ export function createViteConfig({ appDir, config, projectRoot }) {
|
|
|
137
171
|
},
|
|
138
172
|
},
|
|
139
173
|
server: {
|
|
140
|
-
fs: {
|
|
141
|
-
// pages/, lib/ y public/ del usuario viven un nivel arriba de .ecomiq
|
|
142
|
-
allow,
|
|
143
|
-
},
|
|
174
|
+
fs: { allow },
|
|
144
175
|
},
|
|
145
176
|
}
|
|
146
177
|
}
|