@wix/origami-site 0.1.1 → 0.1.3
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 +19 -8
- package/src/browser/index.d.ts +7 -3
- package/src/browser/index.js +57 -1
- package/src/build/globalImports.js +18 -0
- package/src/build/index.d.ts +10 -0
- package/src/build/index.js +15 -0
- package/src/build/pageList.js +37 -0
- package/src/build/sharedPackages.js +14 -0
- package/src/build/transforms.js +27 -0
- package/src/default-error-404.d.ts +4 -0
- package/src/default-error-404.jsx +1 -6
- package/src/vite-plugins/index.d.ts +0 -2
- package/src/vite-plugins/index.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/origami-site",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Runs an exported Wix origami site: file-based routing, Wix dynamic pages, popups and build checks. Use with @wix/origami-site-astro or @wix/origami-site-express.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -9,12 +9,16 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc --noEmit",
|
|
11
11
|
"lint": "oxlint .",
|
|
12
|
-
"test": "node --test test/*.spec.js && tsc --noEmit -p tsconfig.test.json"
|
|
12
|
+
"test": "node --test test/*.spec.js && tsc --noEmit -p tsconfig.test.json && vitest run --config vitest.config.js"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"@types/node": "^22.0.0",
|
|
16
16
|
"typescript": "^6.0.3",
|
|
17
|
-
"vite": "^8"
|
|
17
|
+
"vite": "^8",
|
|
18
|
+
"@vitejs/plugin-react": "^5.2.0",
|
|
19
|
+
"postcss": "^8.5.3",
|
|
20
|
+
"jsdom": "^23.0.1",
|
|
21
|
+
"vitest": "^4.1.11"
|
|
18
22
|
},
|
|
19
23
|
"publishUnscoped": false,
|
|
20
24
|
"publishConfig": {
|
|
@@ -44,6 +48,7 @@
|
|
|
44
48
|
"react-dom": "^18.3.1",
|
|
45
49
|
"@wix/builder-error-pages": "^1.1.6",
|
|
46
50
|
"@wix/builder-piler-components": "^1.6.7",
|
|
51
|
+
"@wix/origami-transforms": "0.1.2",
|
|
47
52
|
"@babel/parser": "^7.25.0"
|
|
48
53
|
},
|
|
49
54
|
"exports": {
|
|
@@ -59,14 +64,20 @@
|
|
|
59
64
|
"types": "./src/popups/index.d.ts",
|
|
60
65
|
"default": "./src/popups/index.js"
|
|
61
66
|
},
|
|
62
|
-
"./
|
|
63
|
-
"types": "./src/
|
|
64
|
-
"default": "./src/
|
|
67
|
+
"./build": {
|
|
68
|
+
"types": "./src/build/index.d.ts",
|
|
69
|
+
"default": "./src/build/index.js"
|
|
65
70
|
},
|
|
66
71
|
"./types": {
|
|
67
72
|
"types": "./src/types/index.d.ts"
|
|
68
73
|
},
|
|
69
|
-
"./default-error-404":
|
|
74
|
+
"./default-error-404": {
|
|
75
|
+
"types": "./src/default-error-404.d.ts",
|
|
76
|
+
"default": "./src/default-error-404.jsx"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"peerDependencies": {
|
|
80
|
+
"vite": "^8"
|
|
70
81
|
},
|
|
71
|
-
"falconPackageHash": "
|
|
82
|
+
"falconPackageHash": "d4e6a231eb25f391006613a9dff797f8a37f0e1a6d465677ef365281"
|
|
72
83
|
}
|
package/src/browser/index.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { PageData } from '../server/index.js'
|
|
2
|
-
|
|
2
|
+
import type { ComponentType } from 'react'
|
|
3
|
+
|
|
4
|
+
export type PageModule = { default: ComponentType }
|
|
3
5
|
export type MountPageOptions = {
|
|
4
|
-
pages: Record<string, () => Promise<
|
|
6
|
+
pages: Record<string, () => Promise<PageModule>>
|
|
5
7
|
popups: Record<string, () => Promise<unknown>>
|
|
6
8
|
seoUriByPageId: Record<string, string>
|
|
7
9
|
beforeMount: () => Promise<unknown>
|
|
8
10
|
}
|
|
9
11
|
export function mountPage(element: Element | null, options: MountPageOptions): Promise<() => void>
|
|
10
|
-
|
|
12
|
+
/** Cached per page load. Warns once and returns undefined if the block is missing.
|
|
13
|
+
* Throws an Error with the parse failure as its cause for invalid JSON. */
|
|
14
|
+
export function readPageData(): PageData | undefined
|
package/src/browser/index.js
CHANGED
|
@@ -1 +1,57 @@
|
|
|
1
|
-
|
|
1
|
+
import { createElement, StrictMode } from 'react'
|
|
2
|
+
import { createRoot } from 'react-dom/client'
|
|
3
|
+
import { PilerPage } from '@wix/builder-piler-components'
|
|
4
|
+
|
|
5
|
+
let hasReadPageData = false
|
|
6
|
+
/** @type {import('../server/index.js').PageData | undefined} */
|
|
7
|
+
let pageData
|
|
8
|
+
/** @type {Error | undefined} */
|
|
9
|
+
let pageDataError
|
|
10
|
+
|
|
11
|
+
/** Read the adapter's JSON block without evaluating it as JavaScript.
|
|
12
|
+
* @returns {import('../server/index.js').PageData | undefined}
|
|
13
|
+
*/
|
|
14
|
+
export function readPageData() {
|
|
15
|
+
if (!hasReadPageData) {
|
|
16
|
+
hasReadPageData = true
|
|
17
|
+
const script = document.getElementById('origami-page')
|
|
18
|
+
if (!script) {
|
|
19
|
+
console.warn('Missing #origami-page data block')
|
|
20
|
+
} else {
|
|
21
|
+
try {
|
|
22
|
+
pageData = JSON.parse(script.textContent ?? '')
|
|
23
|
+
} catch (cause) {
|
|
24
|
+
pageDataError = new Error('Invalid JSON in #origami-page', { cause })
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (pageDataError) throw pageDataError
|
|
29
|
+
return pageData
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @param {Element | null} element
|
|
33
|
+
* @param {import('./index.js').MountPageOptions} options
|
|
34
|
+
* @returns {Promise<() => void>}
|
|
35
|
+
*/
|
|
36
|
+
export async function mountPage(element, { pages, beforeMount }) {
|
|
37
|
+
if (!element) throw new Error('Cannot mount page: root element is missing')
|
|
38
|
+
const data = readPageData()
|
|
39
|
+
const pageKey = data?.page
|
|
40
|
+
const loadPage = (typeof pageKey === 'string' && Object.hasOwn(pages, pageKey) && pages[pageKey])
|
|
41
|
+
|| (Object.hasOwn(pages, 'pages/error404') && pages['pages/error404'])
|
|
42
|
+
|| (Object.hasOwn(pages, '@wix/origami-site/default-error-404') && pages['@wix/origami-site/default-error-404'])
|
|
43
|
+
if (typeof loadPage !== 'function') {
|
|
44
|
+
throw new Error('Cannot mount page: requested page and default 404 are missing')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
await beforeMount()
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error(error)
|
|
51
|
+
}
|
|
52
|
+
// Generated page providers read PageData.services during this import.
|
|
53
|
+
const { default: Page } = await loadPage()
|
|
54
|
+
const root = createRoot(element)
|
|
55
|
+
root.render(createElement(StrictMode, null, createElement(PilerPage, { Page })))
|
|
56
|
+
return () => root.unmount()
|
|
57
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs'
|
|
2
|
+
import { dirname, resolve, sep } from 'node:path'
|
|
3
|
+
|
|
4
|
+
/** @param {string} root
|
|
5
|
+
* @returns {import('vite').Plugin} */
|
|
6
|
+
export const globalImports = root => ({
|
|
7
|
+
name: 'origami:global-imports',
|
|
8
|
+
enforce: /** @type {const} */ ('pre'),
|
|
9
|
+
resolveId(source, importer) {
|
|
10
|
+
if (!importer || source === './' || !(source.startsWith('./') || source.startsWith('../'))) return undefined
|
|
11
|
+
const folder = resolve(dirname(importer.split('?', 1)[0]), source)
|
|
12
|
+
if (!folder.startsWith(`${resolve(root, 'src/global')}${sep}`)) return undefined
|
|
13
|
+
const entry = resolve(folder, '_generated/index.jsx')
|
|
14
|
+
if (existsSync(folder) && statSync(folder).isDirectory() && existsSync(entry) && statSync(entry).isFile())
|
|
15
|
+
return entry
|
|
16
|
+
return undefined
|
|
17
|
+
},
|
|
18
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Plugin } from 'vite'
|
|
2
|
+
import type { OrigamiSite } from '../server/index.js'
|
|
3
|
+
|
|
4
|
+
export type OrigamiVitePluginsOptions = {
|
|
5
|
+
/** The site package folder, containing src/pages/, src/global/, and src/site/ glue. */
|
|
6
|
+
root: string
|
|
7
|
+
/** Shared with the adapter; the plugins do not scan or own the site tree. */
|
|
8
|
+
siteTree: Pick<OrigamiSite, 'table' | 'onTableChange'>
|
|
9
|
+
}
|
|
10
|
+
export function origamiVitePlugins(options: OrigamiVitePluginsOptions): Plugin[]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { transforms } from './transforms.js'
|
|
2
|
+
import { globalImports } from './globalImports.js'
|
|
3
|
+
import { pageList } from './pageList.js'
|
|
4
|
+
import { sharedPackages } from './sharedPackages.js'
|
|
5
|
+
|
|
6
|
+
/** @param {import('./index.js').OrigamiVitePluginsOptions} options
|
|
7
|
+
* @returns {import('vite').Plugin[]} */
|
|
8
|
+
export function origamiVitePlugins({ root, siteTree }) {
|
|
9
|
+
return [
|
|
10
|
+
globalImports(root),
|
|
11
|
+
pageList(siteTree),
|
|
12
|
+
...transforms({ root }),
|
|
13
|
+
sharedPackages(),
|
|
14
|
+
]
|
|
15
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const publicId = 'virtual:origami-site'
|
|
2
|
+
const resolvedId = `\0${publicId}`
|
|
3
|
+
|
|
4
|
+
/** @param {import('@wix/origami-types').SiteRouteTable} table */
|
|
5
|
+
function moduleSource(table) {
|
|
6
|
+
// itemPath is relative to src/ and already includes the pages/ prefix.
|
|
7
|
+
const entries = [...table.pages, table.notFound].map(page => {
|
|
8
|
+
const entry = page.itemPath
|
|
9
|
+
? `/src/${page.itemPath}/_generated/index.jsx`
|
|
10
|
+
: '@wix/origami-site/default-error-404'
|
|
11
|
+
return ` [${JSON.stringify(page.key)}]: () => import(${JSON.stringify(entry)})`
|
|
12
|
+
})
|
|
13
|
+
return `export const pages = {\n${entries.join(',\n')}\n};\nexport const popups = {};\nexport const seoUriByPageId = {};\n`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** @param {import('./index.js').OrigamiVitePluginsOptions['siteTree']} siteTree
|
|
17
|
+
* @returns {import('vite').Plugin} */
|
|
18
|
+
export function pageList(siteTree) {
|
|
19
|
+
/** @type {(() => void) | undefined} */
|
|
20
|
+
let unsubscribe
|
|
21
|
+
return {
|
|
22
|
+
name: 'origami:page-list',
|
|
23
|
+
resolveId(id) { if (id === publicId) return resolvedId },
|
|
24
|
+
async load(id) { if (id === resolvedId) return moduleSource(await siteTree.table()) },
|
|
25
|
+
configureServer(server) {
|
|
26
|
+
unsubscribe?.()
|
|
27
|
+
unsubscribe = siteTree.onTableChange(() => {
|
|
28
|
+
for (const environment of Object.values(server.environments)) {
|
|
29
|
+
const module = environment.moduleGraph.getModuleById(resolvedId)
|
|
30
|
+
if (module) environment.moduleGraph.invalidateModule(module)
|
|
31
|
+
}
|
|
32
|
+
server.ws.send({ type: 'full-reload', path: '*' })
|
|
33
|
+
})
|
|
34
|
+
},
|
|
35
|
+
closeBundle() { unsubscribe?.(); unsubscribe = undefined },
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** @returns {import('vite').Plugin} */
|
|
2
|
+
export function sharedPackages() {
|
|
3
|
+
return {
|
|
4
|
+
name: 'origami:shared-packages',
|
|
5
|
+
config: () => ({ resolve: { dedupe: [
|
|
6
|
+
'react',
|
|
7
|
+
'react-dom',
|
|
8
|
+
'@wix/services-manager-react',
|
|
9
|
+
'@wix/sdk-react-context',
|
|
10
|
+
'@preact/signals-react',
|
|
11
|
+
'@preact/signals-core',
|
|
12
|
+
] } }),
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import { createTransformPipeline } from '@wix/origami-transforms'
|
|
3
|
+
|
|
4
|
+
/** @param {{ root: string }} options
|
|
5
|
+
* @returns {import('vite').Plugin[]} */
|
|
6
|
+
export function transforms({ root }) {
|
|
7
|
+
const pipeline = createTransformPipeline({ layout: { root: resolve(root) } })
|
|
8
|
+
return [
|
|
9
|
+
{
|
|
10
|
+
name: 'origami:jsx-checks',
|
|
11
|
+
enforce: 'pre',
|
|
12
|
+
config(_, { command }) { pipeline.setCommand(command) },
|
|
13
|
+
transform(code, id, options) {
|
|
14
|
+
if (pipeline.appliesTo(id, { ssr: options?.ssr })) return pipeline.transformJsx(code, id, { ssr: options?.ssr })
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'origami:css-transforms',
|
|
19
|
+
config: () => ({ css: { postcss: { plugins: [pipeline.postcssPlugin] } } }),
|
|
20
|
+
handleHotUpdate({ file, server }) {
|
|
21
|
+
if (pipeline.failedStylesheetDependsOn(resolve(file))) {
|
|
22
|
+
server.ws.send({ type: 'full-reload', path: '*' })
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { createRoot } from 'react-dom/client'
|
|
3
1
|
import { DefaultError404 } from '@wix/builder-error-pages'
|
|
4
|
-
import { PilerPage } from '@wix/builder-piler-components'
|
|
5
2
|
import '@wix/builder-error-pages/style.css'
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
React.createElement(React.StrictMode, null, React.createElement(PilerPage, { Page: DefaultError404 }))
|
|
9
|
-
)
|
|
4
|
+
export default DefaultError404
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {}
|