duto 0.261001.0 → 0.261012.0
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 +22 -26
- package/src/commands/templates/pages/components/html.tsx +55 -0
- package/src/commands/templates/pages/components/theme-select.tsx +60 -0
- package/src/commands/templates/pages/i18n/en.ts +6 -0
- package/src/commands/templates/pages/i18n/pt-br.ts +6 -0
- package/src/commands/templates/pages/pages/404.tsx +1 -1
- package/src/commands/templates/pages/pages/blog/[slug].tsx +88 -0
- package/src/commands/templates/pages/pages/blog/index.tsx +74 -0
- package/src/commands/templates/pages/pages/index.tsx +17 -7
- package/src/commands/templates/pages/pages/layout.tsx +5 -3
- package/src/commands/templates/pages/public/favicon.ico +0 -0
- package/src/commands/templates/pages/public/favicon.svg +1 -0
- package/src/commands/templates/pages/style.css +110 -7
- package/src/commands/templates/pages/tsconfig.json +2 -0
- package/src/pages/cli/commands/build.ts +1 -2
- package/src/pages/cli/utils.ts +8 -6
- package/src/pages/client/app.tsx +177 -28
- package/src/pages/client/link.ts +15 -41
- package/src/pages/client/storage.ts +1 -1
- package/src/pages/client/theme.ts +49 -0
- package/src/pages/compiler/ast.ts +13 -0
- package/src/pages/compiler/bun-plugin.ts +245 -0
- package/src/pages/compiler/constants.ts +2 -0
- package/src/pages/compiler/index.ts +44 -23
- package/src/pages/compiler/meta.ts +7 -31
- package/src/pages/compiler/types.ts +15 -25
- package/src/pages/components/link.tsx +11 -19
- package/src/pages/i18n/client.ts +3 -4
- package/src/pages/index.ts +4 -21
- package/src/server/app.ts +2 -1
- package/src/pages/client/router.ts +0 -63
- package/src/pages/compiler/vite-plugin.ts +0 -345
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
// REF: https://github.com/tailwindlabs/tailwindcss/blob/main/packages/%40tailwindcss-vite/src/index.ts
|
|
2
|
-
|
|
3
|
-
import { existsSync, rmSync } from 'node:fs'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import { defineConfig } from 'vite'
|
|
6
|
-
|
|
7
|
-
import preact from '@preact/preset-vite'
|
|
8
|
-
import tailwind from '@tailwindcss/vite'
|
|
9
|
-
import { JSJSON } from 't0n'
|
|
10
|
-
|
|
11
|
-
import { EXT_RE } from './constants'
|
|
12
|
-
import { getChunk, setAsset, setChunk, setEntry } from './assets'
|
|
13
|
-
import { renderPage } from '.'
|
|
14
|
-
import { removeExports, resolveImport } from './ast'
|
|
15
|
-
import { getMetadata } from './meta'
|
|
16
|
-
|
|
17
|
-
import type {
|
|
18
|
-
UserConfig, ConfigEnv, ResolvedConfig,
|
|
19
|
-
// PreviewServer,
|
|
20
|
-
// ViteDevServer,
|
|
21
|
-
EnvironmentOptions,
|
|
22
|
-
PluginOption,
|
|
23
|
-
} from 'vite'
|
|
24
|
-
import type { Metadata, PluginOptions } from './types'
|
|
25
|
-
import { _pages, _root } from '@/utils'
|
|
26
|
-
|
|
27
|
-
const VIRTUAL_ID = ':duto'
|
|
28
|
-
const RESOLVED_ID = '\0'+ VIRTUAL_ID
|
|
29
|
-
|
|
30
|
-
export const config = (opts: UserConfig & PluginOptions) => { // @ts-ignore
|
|
31
|
-
if (!opts.root) opts.root = _root
|
|
32
|
-
if (!opts.pagesDir) opts.pagesDir = 'pages',
|
|
33
|
-
|
|
34
|
-
opts.logLevel = 'silent'
|
|
35
|
-
opts.plugins = [
|
|
36
|
-
...(opts.plugins || []),
|
|
37
|
-
preact(),
|
|
38
|
-
tailwind(),
|
|
39
|
-
plugin(opts),
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
return defineConfig(opts)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// TODO: remover..
|
|
46
|
-
export default config
|
|
47
|
-
|
|
48
|
-
let metadata: Metadata
|
|
49
|
-
export function meta() {
|
|
50
|
-
return metadata
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function plugin(options: PluginOptions = {}): PluginOption[] {
|
|
54
|
-
let config: ResolvedConfig
|
|
55
|
-
const {
|
|
56
|
-
root = _root,
|
|
57
|
-
pagesDir = 'pages',
|
|
58
|
-
} = options
|
|
59
|
-
|
|
60
|
-
const PAGES_RE = new RegExp(`\/${pagesDir}\/.*\.(tsx?|jsx?)$`, 'i')
|
|
61
|
-
const stripTarget = new Set(['getStaticProps'])
|
|
62
|
-
|
|
63
|
-
return [
|
|
64
|
-
{
|
|
65
|
-
name: 'duto:preact-environment',
|
|
66
|
-
|
|
67
|
-
configEnvironment(name, options) {
|
|
68
|
-
const opts: EnvironmentOptions = {optimizeDeps: {}, resolve: {}}
|
|
69
|
-
|
|
70
|
-
if (name === 'client') {
|
|
71
|
-
opts.optimizeDeps!.include = [
|
|
72
|
-
'preact',
|
|
73
|
-
'preact/jsx-runtime',
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
opts.resolve = {dedupe: ['preact/compat', 'preact']}
|
|
78
|
-
|
|
79
|
-
if (name === 'client')
|
|
80
|
-
opts.optimizeDeps!.include!.push(
|
|
81
|
-
'preact/compat',
|
|
82
|
-
// 'preact/test-utils',
|
|
83
|
-
'preact/compat/jsx-runtime',
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
!options.resolve?.noExternal &&
|
|
88
|
-
(name === 'ssr' || name === 'prerender')
|
|
89
|
-
) {
|
|
90
|
-
// noExternal React entrypoints to be bundled, resolved, and aliased by Vite
|
|
91
|
-
opts.resolve!.noExternal = [
|
|
92
|
-
'react',
|
|
93
|
-
'react-dom',
|
|
94
|
-
'react-dom/test-utils',
|
|
95
|
-
'react/jsx-runtime',
|
|
96
|
-
]
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return opts
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
name: 'duto:scan',
|
|
105
|
-
enforce: 'pre',
|
|
106
|
-
|
|
107
|
-
async config(conf: UserConfig, env: ConfigEnv) {
|
|
108
|
-
metadata = await getMetadata(root as string, pagesDir)
|
|
109
|
-
|
|
110
|
-
if (conf.build) {
|
|
111
|
-
// conf.build.emptyOutDir = false
|
|
112
|
-
conf.build.copyPublicDir = false
|
|
113
|
-
conf.build.manifest = false
|
|
114
|
-
conf.build.modulePreload = { polyfill: false }
|
|
115
|
-
|
|
116
|
-
conf.build.minify = metadata.minify
|
|
117
|
-
conf.build.cssMinify = metadata.minify
|
|
118
|
-
|
|
119
|
-
conf.build.rolldownOptions = conf.build.rolldownOptions || {}
|
|
120
|
-
conf.build.rolldownOptions.preserveEntrySignatures = 'exports-only' ///
|
|
121
|
-
conf.build.rolldownOptions.input = [
|
|
122
|
-
...metadata.routes.map(r => r.is404 ? '' : r.fullFilePath).filter(Boolean),
|
|
123
|
-
':duto/client/app.tsx',
|
|
124
|
-
// ':duto/not-found.tsx',
|
|
125
|
-
// ...Object.keys(metadata.pages),
|
|
126
|
-
// ...metadata.assets,
|
|
127
|
-
]
|
|
128
|
-
|
|
129
|
-
const filePrefix = metadata.minify ? '' : '[name].'
|
|
130
|
-
// conf.build.rolldownOptions.input = ':duto/client/app.tsx'
|
|
131
|
-
conf.build.rolldownOptions.output = {
|
|
132
|
-
hoistTransitiveImports: false,
|
|
133
|
-
format: 'esm',
|
|
134
|
-
minifyInternalExports: metadata.minify,
|
|
135
|
-
preserveModulesRoot: '/',
|
|
136
|
-
assetFileNames: filePrefix +'[hash][extname]',
|
|
137
|
-
entryFileNames: filePrefix +'[hash].js',
|
|
138
|
-
chunkFileNames: filePrefix +'[hash].js',
|
|
139
|
-
|
|
140
|
-
// chunkFileNames: '[name].[hash].js',
|
|
141
|
-
// entryFileNames: 'assets/[name].js',
|
|
142
|
-
// chunkFileNames: 'assets/chunks/[name]-[hash].js',
|
|
143
|
-
// assetFileNames: 'assets/[name][extname]',
|
|
144
|
-
|
|
145
|
-
// manualChunks: {
|
|
146
|
-
// vendor: ['preact', '@preact/signals', 'wouter-preact'],
|
|
147
|
-
// },
|
|
148
|
-
// preserveModules: true,
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return conf
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
async configResolved(c) {
|
|
156
|
-
config = c
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
resolveId(id) {
|
|
160
|
-
if (id === VIRTUAL_ID) return RESOLVED_ID
|
|
161
|
-
|
|
162
|
-
if (id.startsWith(':root')) {
|
|
163
|
-
for (const f of [
|
|
164
|
-
'style.css',
|
|
165
|
-
'styles.css',
|
|
166
|
-
'styles/index.css',
|
|
167
|
-
'style/index.css',
|
|
168
|
-
'tailwind.css',
|
|
169
|
-
'tailwindcss.css',
|
|
170
|
-
'styles/tailwind.css',
|
|
171
|
-
'styles/tailwindcss.css',
|
|
172
|
-
]) {
|
|
173
|
-
const path = join(config.root, f)
|
|
174
|
-
if (existsSync(path)) {
|
|
175
|
-
setEntry(id, path)
|
|
176
|
-
return path
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return null
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (!id.startsWith(VIRTUAL_ID)) return null
|
|
184
|
-
|
|
185
|
-
if (EXT_RE.test(id) && id.includes('/')) {
|
|
186
|
-
const path = join(_pages, id.replace(VIRTUAL_ID, ''))
|
|
187
|
-
setEntry(id, path)
|
|
188
|
-
return path
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (id.endsWith('/hmr') && metadata.hmr)
|
|
192
|
-
return join(_pages, 'client', id.replace(VIRTUAL_ID, '') + '.ts')
|
|
193
|
-
|
|
194
|
-
return id.replace(VIRTUAL_ID, RESOLVED_ID)
|
|
195
|
-
},
|
|
196
|
-
|
|
197
|
-
async load(id) {
|
|
198
|
-
if (!id.startsWith(RESOLVED_ID)) return
|
|
199
|
-
|
|
200
|
-
if (id.endsWith('/i18n'))
|
|
201
|
-
return metadata.i18n.string
|
|
202
|
-
|
|
203
|
-
return metadata.string
|
|
204
|
-
},
|
|
205
|
-
|
|
206
|
-
generateBundle(_, bundle) {
|
|
207
|
-
// const moduleIds = this.getModuleIds()
|
|
208
|
-
// for (const id of moduleIds)
|
|
209
|
-
// console.error(id)
|
|
210
|
-
|
|
211
|
-
// TODO: rever isso...
|
|
212
|
-
for (const key in bundle) {
|
|
213
|
-
const file = bundle[key]
|
|
214
|
-
|
|
215
|
-
if (file.type === 'chunk' && file.isEntry) {
|
|
216
|
-
setChunk(file.facadeModuleId, '/'+ file.fileName)
|
|
217
|
-
continue
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (file.type === 'asset' && file?.originalFileName?.endsWith('duto/pages/client/app.tsx'))
|
|
221
|
-
file.source += 'i-i{display:contents}'
|
|
222
|
-
// file.source += 'd-b,d-p,i-d,i-s,i-i{display:contents}'
|
|
223
|
-
|
|
224
|
-
if (file.type === 'asset' && file.fileName.endsWith('.css')) {
|
|
225
|
-
setAsset(resolveImport(file.originalFileName as string, metadata.root, metadata.aliases), '/'+ file.fileName)
|
|
226
|
-
continue
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// console.error(file.fileName)
|
|
230
|
-
// console.error(file.type)
|
|
231
|
-
// console.error(file.viteMetadata)
|
|
232
|
-
// if (file.type !== 'chunk' || !file.isEntry) continue
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
|
|
236
|
-
},
|
|
237
|
-
|
|
238
|
-
// {
|
|
239
|
-
// name: 'duto:routes-inject',
|
|
240
|
-
// enforce: 'post',
|
|
241
|
-
// generateBundle(_, bundle) {
|
|
242
|
-
// // monta o mapa a partir dos inputs de metadata.routes
|
|
243
|
-
// const routeMap: Record<string, string> = {}
|
|
244
|
-
// for (const r of metadata.routes) {
|
|
245
|
-
// if (r.is404) continue
|
|
246
|
-
// // encontra o chunk cujo facadeModuleId bate com r.fullFilePath
|
|
247
|
-
// for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
248
|
-
// if (chunk.type === 'chunk' && chunk.facadeModuleId === r.fullFilePath) {
|
|
249
|
-
// routeMap[r.path] = fileName
|
|
250
|
-
// break
|
|
251
|
-
// }
|
|
252
|
-
// }
|
|
253
|
-
// }
|
|
254
|
-
|
|
255
|
-
// // injeta no chunk do app
|
|
256
|
-
// for (const chunk of Object.values(bundle)) {
|
|
257
|
-
// if (chunk.type !== 'chunk') continue
|
|
258
|
-
// if (chunk.facadeModuleId?.includes('app.tsx') || chunk.code.includes('__DUTO_ROUTES__')) {
|
|
259
|
-
// chunk.code = chunk.code.replace(
|
|
260
|
-
// '__DUTO_ROUTES__',
|
|
261
|
-
// JSON.stringify(routeMap)
|
|
262
|
-
// )
|
|
263
|
-
// }
|
|
264
|
-
// }
|
|
265
|
-
// }
|
|
266
|
-
// },
|
|
267
|
-
{
|
|
268
|
-
name: 'duto:build',
|
|
269
|
-
enforce: 'pre',
|
|
270
|
-
apply: 'build',
|
|
271
|
-
|
|
272
|
-
async buildStart() {
|
|
273
|
-
// if (!server) {
|
|
274
|
-
// const { createServer } = await import('vite')
|
|
275
|
-
// server = await createServer({ server: {middlewareMode: true} })
|
|
276
|
-
// }
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
// teste de import de assets
|
|
280
|
-
// for (const file of metadata.assets) {
|
|
281
|
-
// const id = await this.resolve(file)
|
|
282
|
-
// if (!id) continue
|
|
283
|
-
|
|
284
|
-
// console.error(id)
|
|
285
|
-
// console.error(relative(metadata.root, file).replace(/\.(ts|tsx)$/, '.js'),)
|
|
286
|
-
|
|
287
|
-
// this.emitFile({
|
|
288
|
-
// type: 'chunk',
|
|
289
|
-
// id: id.id,
|
|
290
|
-
// implicitlyLoadedAfterOneOf: [
|
|
291
|
-
// ':duto/app.tsx',
|
|
292
|
-
// ]
|
|
293
|
-
// // fileName: 'assets/[name]-[hash][extname]',
|
|
294
|
-
// // fileName: relative(metadata.root, file).replace(/\.(ts|tsx)$/, '.js'),
|
|
295
|
-
// })
|
|
296
|
-
// }
|
|
297
|
-
|
|
298
|
-
},
|
|
299
|
-
|
|
300
|
-
async closeBundle() {
|
|
301
|
-
for (const [_filePath, page] of metadata.pages)
|
|
302
|
-
await renderPage(metadata, config, page)
|
|
303
|
-
// const mod = await server.ssrLoadModule(_filePath)
|
|
304
|
-
|
|
305
|
-
rmSync(join(metadata.root, 'tmp'), {recursive: true, force: true})
|
|
306
|
-
// await server.close()
|
|
307
|
-
|
|
308
|
-
const outPath = join(config.root, config.build.outDir)
|
|
309
|
-
const entry = Bun.file(join(outPath, getChunk(':duto/client/app.tsx')))
|
|
310
|
-
let entryContent = await entry.text()
|
|
311
|
-
|
|
312
|
-
for (const r of metadata.routes.filter(r => !r.is404))
|
|
313
|
-
entryContent = entryContent.replace(r.fullFilePath, getChunk(r.fullFilePath.replace(config.root, '')))
|
|
314
|
-
|
|
315
|
-
await entry.write(entryContent)
|
|
316
|
-
|
|
317
|
-
// i18n
|
|
318
|
-
for (const locale of metadata.i18n.locales) {
|
|
319
|
-
const intlPath = join(metadata.root, 'i18n', locale + '.ts')
|
|
320
|
-
if (existsSync(intlPath)) {
|
|
321
|
-
const intlMod = await import(intlPath)
|
|
322
|
-
await Bun.write(
|
|
323
|
-
join(outPath, locale +'.js'),
|
|
324
|
-
`var a=${JSJSON({
|
|
325
|
-
routes: intlMod.routes ?? intlMod.default?.routes,
|
|
326
|
-
messages: intlMod.messages ?? intlMod.default?.messages,
|
|
327
|
-
})};export { a as default }`
|
|
328
|
-
)
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
},
|
|
332
|
-
|
|
333
|
-
// TODO: precisa ser aqui mesmo pois se a pagina for importada no entry, pode incluir codigo nao usado no chunck/bundle
|
|
334
|
-
async transform(code, id) {
|
|
335
|
-
if (!PAGES_RE.test(id) || id.includes('node_modules')) return null
|
|
336
|
-
// console.log(this.getModuleInfo(id))
|
|
337
|
-
|
|
338
|
-
const stripped = removeExports(id, code, stripTarget)
|
|
339
|
-
|
|
340
|
-
return (!stripped || stripped === code) ? null : { code: stripped, map: null }
|
|
341
|
-
},
|
|
342
|
-
|
|
343
|
-
},
|
|
344
|
-
]
|
|
345
|
-
}
|