duto 0.0.0 → 0.260808.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/LICENSE +21 -0
- package/README.md +21 -12
- package/package.json +56 -2
- package/src/cli/commands/build.ts +74 -0
- package/src/cli/commands/dev-old.ts +213 -0
- package/src/cli/commands/dev.ts +87 -0
- package/src/cli/commands/preview.ts +33 -0
- package/src/cli/index.ts +28 -0
- package/src/cli/utils.ts +146 -0
- package/src/client/app.tsx +123 -0
- package/src/client/hmr.ts +13 -0
- package/src/client/island.ts +136 -0
- package/src/client/link.ts +70 -0
- package/src/client/router.ts +329 -0
- package/src/client/storage.ts +95 -0
- package/src/compiler/aliases.ts +36 -0
- package/src/compiler/assets.ts +43 -0
- package/src/compiler/ast.ts +764 -0
- package/src/compiler/constants.ts +24 -0
- package/src/compiler/file.ts +60 -0
- package/src/compiler/index.ts +307 -0
- package/src/compiler/island.ts +108 -0
- package/src/compiler/meta.ts +601 -0
- package/src/compiler/routes.ts +29 -0
- package/src/compiler/types.ts +209 -0
- package/src/compiler/utils.ts +5 -0
- package/src/compiler/vite-plugin.ts +324 -0
- package/src/components/link.tsx +38 -0
- package/src/i18n/client.ts +403 -0
- package/src/i18n/element.ts +44 -0
- package/src/i18n/server.ts +56 -0
- package/src/index.ts +28 -0
- package/src/preact/client-dev.ts +5 -0
- package/src/preact/client.ts +87 -0
- package/src/preact/context.ts +41 -0
- package/src/preact/server.ts +186 -0
- package/src/preact/signals.ts +89 -0
- package/src/preact/static-html.ts +45 -0
- package/src/preact/types.ts +26 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// import type { ComponentType, FunctionComponent, VNode } from 'preact'
|
|
2
|
+
import type { FunctionComponent, VNode } from 'preact'
|
|
3
|
+
|
|
4
|
+
export type PluginOptions = {
|
|
5
|
+
root?: string,
|
|
6
|
+
// Directory to scan for pages, relative to Vite root. Default: "./pages"
|
|
7
|
+
pagesDir?: string,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type DepMetadata = {
|
|
11
|
+
path: string,
|
|
12
|
+
ref: string,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type FileMetadata = {
|
|
16
|
+
path: string,
|
|
17
|
+
content: string,
|
|
18
|
+
deps: Map<string, DepMetadata>,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type I18nMetadata = {
|
|
22
|
+
fallbackLocale: string,
|
|
23
|
+
locales: string[],
|
|
24
|
+
messages: Record<string, Record<string, string>>,
|
|
25
|
+
routes: Record<string, Record<string, string>>,
|
|
26
|
+
routeMap: Record<string, string>,
|
|
27
|
+
pageRoutes: { locale: string, path: string }[]
|
|
28
|
+
options: Record<string, string>,
|
|
29
|
+
string: string,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type SummaryMetadata = {
|
|
33
|
+
type: number,
|
|
34
|
+
path: string,
|
|
35
|
+
size: number,
|
|
36
|
+
sizeBr: number,
|
|
37
|
+
sizeJS: number,
|
|
38
|
+
children?: Map<string, SummaryMetadata>,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type Metadata = {
|
|
42
|
+
root: string,
|
|
43
|
+
dir: string,
|
|
44
|
+
aliases: Record<string, string>,
|
|
45
|
+
map: Map<string, FileMetadata>,
|
|
46
|
+
violations: Map<string, DepMetadata[]>,
|
|
47
|
+
layouts: Map<string, IRoute>, // all layouts
|
|
48
|
+
nf: Map<string, IRoute>, // all 404
|
|
49
|
+
pages: Map<string, IRoute>, // all
|
|
50
|
+
spages: Set<string>, // ssg pages
|
|
51
|
+
routes: Routes, // client-side
|
|
52
|
+
// routes: Map<string, IRoute>, // client-side
|
|
53
|
+
assets: string[],
|
|
54
|
+
i18n: I18nMetadata,
|
|
55
|
+
string: string,
|
|
56
|
+
summary: Map<string, SummaryMetadata>,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type Page<P = {}> = FunctionComponent<VNode<P>>
|
|
60
|
+
// A page module as imported by Bun/Vite
|
|
61
|
+
export type PageModule<P = {}> = {
|
|
62
|
+
default: Page<P>,
|
|
63
|
+
// default: ComponentType<VNode<any>>,
|
|
64
|
+
getStaticProps?: GetStaticProps,
|
|
65
|
+
getProps?: GetProps,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* getStaticProps — build-only.
|
|
70
|
+
* For static pages (no dynamic segments): returns a single props object.
|
|
71
|
+
* For dynamic pages: returns an array of { [routeParam]: value, ...props }
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
export type GetStaticProps =
|
|
75
|
+
| (() => StaticProps | Promise<StaticProps>)
|
|
76
|
+
| (() => StaticProps[] | Promise<StaticProps[]>)
|
|
77
|
+
export type StaticProps = Record<string, unknown>
|
|
78
|
+
|
|
79
|
+
/** browser-only */
|
|
80
|
+
// export type $duto = {
|
|
81
|
+
// sroutes: Set<string>,
|
|
82
|
+
// navigate: {},
|
|
83
|
+
// route: { pattern: string, params: RouteParams, path: string },
|
|
84
|
+
// }
|
|
85
|
+
export type GetProps = (params: RouteParams) => StaticProps | Promise<StaticProps>
|
|
86
|
+
export type RouteParams = Record<string, string | string[] | undefined>
|
|
87
|
+
|
|
88
|
+
export type Routes = IRoute[]
|
|
89
|
+
export type IRoute = {
|
|
90
|
+
content: string,
|
|
91
|
+
mod: PageModule,
|
|
92
|
+
/** True if the page exports getStaticProps */
|
|
93
|
+
hasGetStaticProps: boolean,
|
|
94
|
+
/** True if the page exports getProps */
|
|
95
|
+
hasGetProps: boolean,
|
|
96
|
+
isClientOnly: boolean,
|
|
97
|
+
islands: ImportUsage[], // TODO mover para cá
|
|
98
|
+
// islands: IslandMeta[],
|
|
99
|
+
// safeFilePath: string,
|
|
100
|
+
layouts: IRoute[],
|
|
101
|
+
importName: string,
|
|
102
|
+
|
|
103
|
+
////////////////////////////
|
|
104
|
+
|
|
105
|
+
fileExt: string,
|
|
106
|
+
fileName: string,
|
|
107
|
+
/** Original file path relative to pages dir, e.g. `blog/[slug].tsx` */
|
|
108
|
+
filePath: string,
|
|
109
|
+
fullFilePath: string,
|
|
110
|
+
/** Wouter-compatible pattern, e.g. `/blog/:slug` */
|
|
111
|
+
pattern: string,
|
|
112
|
+
/** Params extracted from the path segments */
|
|
113
|
+
params: Record<string, RouteParam>,
|
|
114
|
+
// params: RouteParam[],
|
|
115
|
+
/**
|
|
116
|
+
* Similar to the "params" field, but with more associated metadata. For example, for `/site/[blog]/[...slug].tsx`, the segments are:
|
|
117
|
+
*
|
|
118
|
+
* 1. `{ content: 'site', dynamic: false, spread: false }`
|
|
119
|
+
* 2. `{ content: 'blog', dynamic: true, spread: false }`
|
|
120
|
+
* 3. `{ content: '...slug', dynamic: true, spread: true }`
|
|
121
|
+
*/
|
|
122
|
+
// segments: RoutePart[][]; // alternativa ao "params"
|
|
123
|
+
is404: boolean,
|
|
124
|
+
/** True if this route has any dynamic segments */
|
|
125
|
+
isDynamic: boolean,
|
|
126
|
+
/** True if this route are internal */
|
|
127
|
+
isInternal: boolean,
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type RouteParam = {
|
|
131
|
+
name: string,
|
|
132
|
+
optional: boolean,
|
|
133
|
+
catchAll: boolean,
|
|
134
|
+
value?: string | string[],
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
export interface Usage {
|
|
140
|
+
type: 'jsx' | 'call' | 'reference'
|
|
141
|
+
source: string,
|
|
142
|
+
imported: string,
|
|
143
|
+
local: string,
|
|
144
|
+
start: number,
|
|
145
|
+
end: number,
|
|
146
|
+
text: string,
|
|
147
|
+
node: unknown,
|
|
148
|
+
parent: unknown,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface ImportUsage {
|
|
152
|
+
source: string,
|
|
153
|
+
imported: string,
|
|
154
|
+
local: string,
|
|
155
|
+
importStart: number,
|
|
156
|
+
importEnd: number,
|
|
157
|
+
importText: string,
|
|
158
|
+
usages: Usage[],
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface IslandMeta {
|
|
162
|
+
/** Identificador curto e único (base64url de 7 chars) */
|
|
163
|
+
id: string
|
|
164
|
+
/** URL pública do asset JS do componente */
|
|
165
|
+
url: string
|
|
166
|
+
/** Nome do export usado */
|
|
167
|
+
export: string
|
|
168
|
+
/** Props serializadas como JSON (HTML-encoded) */
|
|
169
|
+
props: string
|
|
170
|
+
/** HTML do SSR do componente */
|
|
171
|
+
ssrHtml: string
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// export interface ReplaceIslandsOptions {
|
|
175
|
+
// /**
|
|
176
|
+
// * Função que resolve o nome do componente para a URL pública do asset JS.
|
|
177
|
+
// * Ex: 'Counter' → '/assets/Counter.BQxoyJbC.js'
|
|
178
|
+
// */
|
|
179
|
+
// resolveUrl: (exportName: string) => string
|
|
180
|
+
// /**
|
|
181
|
+
// * Função que carrega o módulo do componente para fazer SSR.
|
|
182
|
+
// * Recebe o source da importação (ex: '@/components/counter2') e o nome do export.
|
|
183
|
+
// */
|
|
184
|
+
// loadComponent: (source: string, exportName: string) => Promise<unknown>
|
|
185
|
+
// }
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
// export type Island = {
|
|
189
|
+
// /** Unique id — written as data-island on the placeholder div */
|
|
190
|
+
// id: string,
|
|
191
|
+
// /** Component display name — used by the client to look up the component */
|
|
192
|
+
// name: string,
|
|
193
|
+
// /** Props serialised into the placeholder for client hydration */
|
|
194
|
+
// props: Record<string, unknown>,
|
|
195
|
+
// }
|
|
196
|
+
|
|
197
|
+
// export type RenderResult = {
|
|
198
|
+
// html: string,
|
|
199
|
+
// islands: Island[],
|
|
200
|
+
// /** true if any islands were found (= client JS needed) */
|
|
201
|
+
// hasIslands: boolean,
|
|
202
|
+
// }
|
|
203
|
+
|
|
204
|
+
// export type IslandMeta = {
|
|
205
|
+
// id: string,
|
|
206
|
+
// name: string,
|
|
207
|
+
// props: Record<string, unknown>,
|
|
208
|
+
// }
|
|
209
|
+
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
// REF: https://github.com/tailwindlabs/tailwindcss/blob/main/packages/%40tailwindcss-vite/src/index.ts
|
|
2
|
+
|
|
3
|
+
import { existsSync, readFileSync, 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
|
+
|
|
10
|
+
import { EXT_RE } from './constants'
|
|
11
|
+
import { setAsset, setChunk, setEntry } from './assets'
|
|
12
|
+
import { renderPage } from './'
|
|
13
|
+
import { removeExports, resolveImport } from './ast'
|
|
14
|
+
import { getMetadata } from './meta'
|
|
15
|
+
|
|
16
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
17
|
+
import type {
|
|
18
|
+
// Plugin,
|
|
19
|
+
UserConfig, ConfigEnv, ResolvedConfig,
|
|
20
|
+
PreviewServer,
|
|
21
|
+
// ViteDevServer,
|
|
22
|
+
EnvironmentOptions,
|
|
23
|
+
PluginOption,
|
|
24
|
+
} from 'vite'
|
|
25
|
+
import type { Metadata, PluginOptions } from './types'
|
|
26
|
+
import { _duto, _root } from './utils'
|
|
27
|
+
|
|
28
|
+
const VIRTUAL_ID = ':duto'
|
|
29
|
+
const RESOLVED_ID = '\0'+ VIRTUAL_ID
|
|
30
|
+
|
|
31
|
+
export const config = (opts: UserConfig & PluginOptions) => {
|
|
32
|
+
if (!opts.root) opts.root = _root
|
|
33
|
+
if (!opts.pagesDir) opts.pagesDir = 'pages',
|
|
34
|
+
|
|
35
|
+
opts.logLevel = 'silent'
|
|
36
|
+
opts.plugins = [
|
|
37
|
+
...(opts.plugins || []),
|
|
38
|
+
preact(),
|
|
39
|
+
tailwind(),
|
|
40
|
+
plugin(opts),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
return defineConfig(opts)
|
|
44
|
+
}
|
|
45
|
+
|
|
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 server: ViteDevServer
|
|
55
|
+
let config: ResolvedConfig
|
|
56
|
+
const {
|
|
57
|
+
root = _root, // process.env.npm_config_local_prefix || process.env.PWD || process.cwd() || __dirname,
|
|
58
|
+
pagesDir = 'pages',
|
|
59
|
+
} = options
|
|
60
|
+
|
|
61
|
+
// let metadata: Metadata
|
|
62
|
+
|
|
63
|
+
const PAGES_RE = new RegExp(`\/${pagesDir}\/.*\.(tsx?|jsx?)$`, 'i')
|
|
64
|
+
const stripTarget = new Set(['getStaticProps'])
|
|
65
|
+
|
|
66
|
+
return [
|
|
67
|
+
{
|
|
68
|
+
name: 'duto:preact-environment',
|
|
69
|
+
|
|
70
|
+
configEnvironment(name, options) {
|
|
71
|
+
const opts: EnvironmentOptions = {optimizeDeps: {}, resolve: {}}
|
|
72
|
+
|
|
73
|
+
if (name === 'client') {
|
|
74
|
+
opts.optimizeDeps!.include = [
|
|
75
|
+
'preact',
|
|
76
|
+
'preact/jsx-runtime',
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
opts.resolve = {dedupe: ['preact/compat', 'preact']}
|
|
81
|
+
|
|
82
|
+
if (name === 'client')
|
|
83
|
+
opts.optimizeDeps!.include!.push(
|
|
84
|
+
'preact/compat',
|
|
85
|
+
// 'preact/test-utils',
|
|
86
|
+
'preact/compat/jsx-runtime',
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if (
|
|
90
|
+
!options.resolve?.noExternal &&
|
|
91
|
+
(name === 'ssr' || name === 'prerender')
|
|
92
|
+
) {
|
|
93
|
+
// noExternal React entrypoints to be bundled, resolved, and aliased by Vite
|
|
94
|
+
opts.resolve!.noExternal = [
|
|
95
|
+
'react',
|
|
96
|
+
'react-dom',
|
|
97
|
+
'react-dom/test-utils',
|
|
98
|
+
'react/jsx-runtime',
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return opts
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
// configurePreviewServer(server: PreviewServer) {
|
|
106
|
+
// const distDir = join(server.config.root, 'dist')
|
|
107
|
+
|
|
108
|
+
// server.middlewares.use((req: IncomingMessage, res: ServerResponse, next: (err?: any) => void) => {
|
|
109
|
+
// if (req.url && !existsSync(join(distDir, req.url.split('?')[0]))) {
|
|
110
|
+
// const notFound = join(distDir, '404.html')
|
|
111
|
+
|
|
112
|
+
// if (existsSync(notFound)) {
|
|
113
|
+
// res.statusCode = 404
|
|
114
|
+
// res.setHeader('Content-Type', 'text/html')
|
|
115
|
+
// .end(readFileSync(notFound, 'utf-8'))
|
|
116
|
+
// return
|
|
117
|
+
// }
|
|
118
|
+
// }
|
|
119
|
+
|
|
120
|
+
// next()
|
|
121
|
+
// })
|
|
122
|
+
// },
|
|
123
|
+
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
{
|
|
127
|
+
name: 'duto:scan',
|
|
128
|
+
enforce: 'pre',
|
|
129
|
+
|
|
130
|
+
// configureServer(_server) {
|
|
131
|
+
// server = _server
|
|
132
|
+
// // servers.push(server)
|
|
133
|
+
// },
|
|
134
|
+
|
|
135
|
+
async config(conf: UserConfig, env: ConfigEnv) {
|
|
136
|
+
// if (!metadata)
|
|
137
|
+
metadata = await getMetadata(root, pagesDir)
|
|
138
|
+
|
|
139
|
+
// console.log(metadata.map)
|
|
140
|
+
// console.log(metadata.violations)
|
|
141
|
+
// console.log(Array.from(metadata.violations).filter(file => EXT_RE.test(file)))
|
|
142
|
+
|
|
143
|
+
if (conf.build) {
|
|
144
|
+
// conf.build.emptyOutDir = false
|
|
145
|
+
conf.build.copyPublicDir = false
|
|
146
|
+
conf.build.manifest = false
|
|
147
|
+
conf.build.modulePreload = { polyfill: false }
|
|
148
|
+
|
|
149
|
+
conf.build.minify = true
|
|
150
|
+
conf.build.cssMinify = true //////
|
|
151
|
+
|
|
152
|
+
conf.build.rolldownOptions = conf.build.rolldownOptions || {}
|
|
153
|
+
conf.build.rolldownOptions.preserveEntrySignatures = 'exports-only' ///
|
|
154
|
+
conf.build.rolldownOptions.input = [
|
|
155
|
+
':duto/client/app.tsx',
|
|
156
|
+
// ':duto/not-found.tsx',
|
|
157
|
+
...Object.keys(metadata.pages),
|
|
158
|
+
...metadata.assets,
|
|
159
|
+
]
|
|
160
|
+
// conf.build.rolldownOptions.input = ':duto/client/app.tsx'
|
|
161
|
+
conf.build.rolldownOptions.output = {
|
|
162
|
+
hoistTransitiveImports: false,
|
|
163
|
+
format: 'esm',
|
|
164
|
+
minifyInternalExports: true,
|
|
165
|
+
|
|
166
|
+
// manualChunks: {
|
|
167
|
+
// vendor: ['preact', '@preact/signals', 'wouter-preact'],
|
|
168
|
+
// },
|
|
169
|
+
// preserveModules: true,
|
|
170
|
+
preserveModulesRoot: '/',
|
|
171
|
+
assetFileNames: '[hash][extname]',
|
|
172
|
+
entryFileNames: '[hash].js',
|
|
173
|
+
chunkFileNames: '[hash].js',
|
|
174
|
+
|
|
175
|
+
// chunkFileNames: '[name].[hash].js',
|
|
176
|
+
// entryFileNames: 'assets/[name].js',
|
|
177
|
+
// chunkFileNames: 'assets/chunks/[name]-[hash].js',
|
|
178
|
+
// assetFileNames: 'assets/[name][extname]',
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return conf
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
async configResolved(conf) {
|
|
186
|
+
config = conf
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
resolveId(id) {
|
|
190
|
+
if (id === VIRTUAL_ID) return RESOLVED_ID
|
|
191
|
+
|
|
192
|
+
if (id.startsWith(':root')) {
|
|
193
|
+
for (const f of [
|
|
194
|
+
'style.css',
|
|
195
|
+
'styles.css',
|
|
196
|
+
'styles/index.css',
|
|
197
|
+
'style/index.css',
|
|
198
|
+
'tailwind.css',
|
|
199
|
+
'tailwindcss.css',
|
|
200
|
+
'styles/tailwind.css',
|
|
201
|
+
'styles/tailwindcss.css',
|
|
202
|
+
]) {
|
|
203
|
+
const path = join(config.root, f)
|
|
204
|
+
if (existsSync(path)) {
|
|
205
|
+
setEntry(id, path)
|
|
206
|
+
return path
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return null
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!id.startsWith(VIRTUAL_ID)) return null
|
|
214
|
+
|
|
215
|
+
if (EXT_RE.test(id) && id.includes('/')) {
|
|
216
|
+
const path = join(_duto, id.replace(VIRTUAL_ID, ''))
|
|
217
|
+
setEntry(id, path)
|
|
218
|
+
return path
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (id.endsWith('/hmr') && global.__hmr)
|
|
222
|
+
return join(_duto, id.replace(VIRTUAL_ID, '') + '.ts')
|
|
223
|
+
|
|
224
|
+
return id.replace(VIRTUAL_ID, RESOLVED_ID)
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
async load(id) {
|
|
228
|
+
if (!id.startsWith(RESOLVED_ID)) return
|
|
229
|
+
|
|
230
|
+
if (id.endsWith('/i18n'))
|
|
231
|
+
return metadata.i18n.string
|
|
232
|
+
|
|
233
|
+
return metadata.string
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
generateBundle(_, bundle) {
|
|
237
|
+
// const moduleIds = this.getModuleIds()
|
|
238
|
+
// for (const id of moduleIds)
|
|
239
|
+
// console.error(id)
|
|
240
|
+
|
|
241
|
+
for (const key in bundle) {
|
|
242
|
+
const file = bundle[key]
|
|
243
|
+
if (file.type === 'chunk' && file.isEntry) {
|
|
244
|
+
setChunk(file.facadeModuleId, '/'+ file.fileName)
|
|
245
|
+
continue
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (file.type === 'asset' && file?.originalFileName?.endsWith('duto/client/app.tsx'))
|
|
249
|
+
file.source += 'd-b,d-p,i-d,i-s,i-i{display:contents}'
|
|
250
|
+
|
|
251
|
+
if (file.type === 'asset' && file.fileName.endsWith('.css')) {
|
|
252
|
+
setAsset(resolveImport(file.originalFileName as string, metadata.root, metadata.aliases), '/'+ file.fileName)
|
|
253
|
+
continue
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// console.error(file.fileName)
|
|
257
|
+
// console.error(file.type)
|
|
258
|
+
// console.error(file.viteMetadata)
|
|
259
|
+
// if (file.type !== 'chunk' || !file.isEntry) continue
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
{
|
|
266
|
+
name: 'duto:build',
|
|
267
|
+
enforce: 'pre',
|
|
268
|
+
apply: 'build',
|
|
269
|
+
|
|
270
|
+
async buildStart() {
|
|
271
|
+
// if (!server) {
|
|
272
|
+
// const { createServer } = await import('vite')
|
|
273
|
+
// server = await createServer({ server: {middlewareMode: true} })
|
|
274
|
+
// }
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
// teste de import de assets
|
|
278
|
+
// for (const file of metadata.assets) {
|
|
279
|
+
// const id = await this.resolve(file)
|
|
280
|
+
// if (!id) continue
|
|
281
|
+
|
|
282
|
+
// console.error(id)
|
|
283
|
+
// console.error(relative(metadata.root, file).replace(/\.(ts|tsx)$/, '.js'),)
|
|
284
|
+
|
|
285
|
+
// this.emitFile({
|
|
286
|
+
// type: 'chunk',
|
|
287
|
+
// id: id.id,
|
|
288
|
+
// implicitlyLoadedAfterOneOf: [
|
|
289
|
+
// ':duto/app.tsx',
|
|
290
|
+
// ]
|
|
291
|
+
// // fileName: 'assets/[name]-[hash][extname]',
|
|
292
|
+
// // fileName: relative(metadata.root, file).replace(/\.(ts|tsx)$/, '.js'),
|
|
293
|
+
// })
|
|
294
|
+
// }
|
|
295
|
+
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
async closeBundle() {
|
|
299
|
+
for (const [_filePath, page] of metadata.pages) {
|
|
300
|
+
await renderPage(metadata, config, page)
|
|
301
|
+
// const mod = await server.ssrLoadModule(_filePath)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
rmSync(join(metadata.root, 'tmp'), {recursive: true, force: true})
|
|
305
|
+
// await server.close()
|
|
306
|
+
},
|
|
307
|
+
|
|
308
|
+
// TODO: precisa ser aqui mesmo pois se a pagina for importada no entry, pode incluir codigo nao usado no chunck/bundle
|
|
309
|
+
async transform(code, id) {
|
|
310
|
+
if (!PAGES_RE.test(id) || id.includes('node_modules')) return null
|
|
311
|
+
// console.log(this.getModuleInfo(id))
|
|
312
|
+
|
|
313
|
+
const stripped = removeExports(id, code, stripTarget)
|
|
314
|
+
if (!stripped || stripped === code) return null
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
code: stripped,
|
|
318
|
+
map: null, // source maps omitted for brevity, add if needed
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
},
|
|
323
|
+
]
|
|
324
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Link as WouterLink, useLocation } from 'wouter-preact'
|
|
2
|
+
import type { LinkProps } from 'wouter-preact'
|
|
3
|
+
|
|
4
|
+
const isExternalUrl = (href?: string) =>
|
|
5
|
+
href ? href.startsWith('http')
|
|
6
|
+
|| href.startsWith('//')
|
|
7
|
+
|| href.startsWith('mailto:')
|
|
8
|
+
|| href.startsWith('tel:') : false
|
|
9
|
+
|
|
10
|
+
export const Link = ({
|
|
11
|
+
to = '',
|
|
12
|
+
href = to,
|
|
13
|
+
...rest
|
|
14
|
+
}: LinkProps) => {
|
|
15
|
+
const isExternal = isExternalUrl(rest.href = href)
|
|
16
|
+
const isSRoute = window?.$duto?.sroutes?.has(href)
|
|
17
|
+
|
|
18
|
+
if (isExternal) {
|
|
19
|
+
rest.target = '_blank'
|
|
20
|
+
rest.rel = 'noopener noreferrer'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!href || isExternal || isSRoute) {
|
|
24
|
+
const [pathname] = useLocation()
|
|
25
|
+
const baseClass = typeof rest.class === 'string' || !rest?.class
|
|
26
|
+
? (rest.class || '') as string
|
|
27
|
+
: ''
|
|
28
|
+
rest.class = baseClass + (pathname === href ? ' active' : '')
|
|
29
|
+
|
|
30
|
+
!href && (delete rest.href)
|
|
31
|
+
return <a is='i-l' {...rest} />
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof rest.class === 'string' || !rest?.class)
|
|
35
|
+
rest.className = a => (rest.class || '') + (a ? ' active' : '')
|
|
36
|
+
|
|
37
|
+
return <WouterLink is='i-l' {...rest} />
|
|
38
|
+
}
|