@woodsportal/hubspot-kit 1.0.37 → 1.0.39-dev.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/CHANGELOG.md +13 -0
- package/examples/fixtures/adopted-module-hybrid/.wphs/.gitkeep +0 -0
- package/examples/fixtures/adopted-module-monolith/.wphs/.gitkeep +0 -0
- package/examples/fixtures/adopted-theme-minimal/.wphs/.gitkeep +0 -0
- package/package.json +23 -9
- package/scripts/vite/create-dev-server-config.mjs +1 -0
- package/scripts/vite/resolve-from-project-root.js +19 -0
- package/scripts/vite/resolve-from-project-root.test.mjs +37 -0
- package/src/dev-module-config/runtime/module-config-runtime.ts +1 -0
- package/src/dev-module-config/ui/ModuleConfigShell.tsx +6 -1
- package/src/dev-module-config/ui/use-module-config.ts +43 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
### CI / CodeBuild
|
|
6
|
+
- **`woodsportal-<env>-cb-hubspot-kit-publish`** — `hubspot-kit-npm-publish.yml` runs `npm run verify` then publishes `@woodsportal/hubspot-kit` (`next` on `dev`, `latest` on `main`). Client-frontend node-push installs kit from npm via `HUBSPOT_KIT_NPM_TAG` override.
|
|
7
|
+
|
|
5
8
|
### Module build id (collaborative CDN deploys)
|
|
6
9
|
- **Rename** `.portal-build-id` → `.module-build-id` (channel baseline); `wp migrate --yes` upgrades legacy projects
|
|
7
10
|
- **Auto-bump** on `wp deploy` and `wp build --cdn-only` — `{baseline}.{devSlug}.{seq}` in gitignored `.wphs/state/module-build-id.json`
|
|
@@ -19,6 +22,16 @@
|
|
|
19
22
|
- **CSS entries** — shared `tailwind.css.config.css`; documented never-merge rules on `main.dev.css` / `main.prod.css`
|
|
20
23
|
- **`wp doctor`** — CSS pipeline checks (prefix, `.temp` @source, `skipRuntimeCss`, `module.css` dw utilities, CDN `require_css` warning)
|
|
21
24
|
|
|
25
|
+
## 1.0.39 — 2026-06-08
|
|
26
|
+
|
|
27
|
+
### Dev server
|
|
28
|
+
- **Module-config overlay** — sync runtime state on mount and after init (fixes stuck "Loading module config…" when Vite loads duplicate module copies); pin `@woodsportal/hubspot-kit/src/dev-module-config` to `.wphs/.kit-module-config`
|
|
29
|
+
|
|
30
|
+
## 1.0.38 — 2026-06-08
|
|
31
|
+
|
|
32
|
+
### Dev server
|
|
33
|
+
- **Module-config overlay** — stop force-resolving `react` / `react-dom` to CJS `index.js` for kit UI under `.wphs/`; fixes `createContext` / named export errors in the browser on `yarn local`
|
|
34
|
+
|
|
22
35
|
## 1.0.37 — 2026-06-08
|
|
23
36
|
|
|
24
37
|
### Dev server
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@woodsportal/hubspot-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.39-dev.0",
|
|
4
4
|
"description": "WoodsCLI — HubSpot CMS dev kit by WoodsPortal. wp CLI, Vite presets, module-config overlay, and theme/module build pipelines.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"build": "tsup",
|
|
52
52
|
"dev": "tsup --watch",
|
|
53
53
|
"typecheck": "tsc --noEmit",
|
|
54
|
-
"test": "node --import tsx --test 'src/lib/**/*.test.ts' 'src/schema/**/*.test.ts' 'src/vite/**/*.test.ts' 'scripts/portal-build-id.test.mjs' 'scripts/resolve-consumer-dep.test.mjs' 'scripts/vite/ensure-dev-kit-shims.test.mjs' 'scripts/vite/consumer-react-aliases.test.mjs' && vitest run src/dev-module-config/__tests__/normalize-repeater-items.test.ts src/dev-module-config/__tests__/module-config-transform.test.ts src/dev-module-config/__tests__/flatten-visible-fields.test.ts",
|
|
54
|
+
"test": "node --import tsx --test 'src/lib/**/*.test.ts' 'src/schema/**/*.test.ts' 'src/vite/**/*.test.ts' 'scripts/portal-build-id.test.mjs' 'scripts/resolve-consumer-dep.test.mjs' 'scripts/vite/ensure-dev-kit-shims.test.mjs' 'scripts/vite/consumer-react-aliases.test.mjs' 'scripts/vite/resolve-from-project-root.test.mjs' && vitest run src/dev-module-config/__tests__/normalize-repeater-items.test.ts src/dev-module-config/__tests__/module-config-transform.test.ts src/dev-module-config/__tests__/flatten-visible-fields.test.ts",
|
|
55
55
|
"test:examples": "node examples/smoke/run-matrix.mjs --tier static",
|
|
56
56
|
"lint": "eslint src",
|
|
57
57
|
"verify": "npm run typecheck && npm run test && npm run test:examples && npm run build",
|
|
@@ -87,12 +87,26 @@
|
|
|
87
87
|
"vite": "^6.0.0"
|
|
88
88
|
},
|
|
89
89
|
"peerDependenciesMeta": {
|
|
90
|
-
"@tailwindcss/vite": {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"
|
|
90
|
+
"@tailwindcss/vite": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
93
|
+
"@tanstack/router-plugin": {
|
|
94
|
+
"optional": true
|
|
95
|
+
},
|
|
96
|
+
"@vitejs/plugin-react": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
99
|
+
"babel-plugin-react-compiler": {
|
|
100
|
+
"optional": true
|
|
101
|
+
},
|
|
102
|
+
"react": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"react-dom": {
|
|
106
|
+
"optional": true
|
|
107
|
+
},
|
|
108
|
+
"vite": {
|
|
109
|
+
"optional": true
|
|
110
|
+
}
|
|
97
111
|
}
|
|
98
112
|
}
|
|
@@ -73,6 +73,7 @@ export async function createDevServerViteConfig(options = {}) {
|
|
|
73
73
|
alias: {
|
|
74
74
|
...consumerReactAliases(projectRoot),
|
|
75
75
|
'@/dev/module-config': moduleConfigRoot,
|
|
76
|
+
'@woodsportal/hubspot-kit/src/dev-module-config': moduleConfigRoot,
|
|
76
77
|
'@wphs/bootstrap': bootstrapShim,
|
|
77
78
|
'@wphs/bootstrap-greenfield': bootstrapGreenfieldShim,
|
|
78
79
|
'@woodsportal/hubspot-kit/dev/bootstrap': bootstrapShim,
|
|
@@ -2,6 +2,22 @@ import { resolve, sep } from 'node:path'
|
|
|
2
2
|
|
|
3
3
|
import { resolveConsumerDep } from '../resolve-consumer-dep.mjs'
|
|
4
4
|
|
|
5
|
+
/** Let Vite dedupe + optimizeDeps handle React; forced absolute paths serve CJS in the browser. */
|
|
6
|
+
export const SKIP_CONSUMER_RESOLVE_SPECS = new Set([
|
|
7
|
+
'react',
|
|
8
|
+
'react-dom',
|
|
9
|
+
'react/jsx-runtime',
|
|
10
|
+
'react/jsx-dev-runtime',
|
|
11
|
+
'react-dom/client',
|
|
12
|
+
'react/compiler-runtime',
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
function shouldSkipConsumerResolve(source) {
|
|
16
|
+
if (SKIP_CONSUMER_RESOLVE_SPECS.has(source)) return true
|
|
17
|
+
if (source.startsWith('react/') || source.startsWith('react-dom/')) return true
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
5
21
|
/**
|
|
6
22
|
* When Vite transforms kit dev UI (`.wphs/`, package src, or dev-module-config),
|
|
7
23
|
* bare imports must resolve from the consumer project's node_modules.
|
|
@@ -29,6 +45,9 @@ export default function resolveFromProjectRoot(projectRoot, kitRoot) {
|
|
|
29
45
|
if (!isKitUiImporter(importer)) {
|
|
30
46
|
return null
|
|
31
47
|
}
|
|
48
|
+
if (shouldSkipConsumerResolve(source)) {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
32
51
|
try {
|
|
33
52
|
return resolveConsumerDep(source, projectRoot)
|
|
34
53
|
} catch {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { describe, it } from 'node:test'
|
|
4
|
+
|
|
5
|
+
import { consumerDepFixtureRoot } from '../test-fixtures/consumer-dep-fixture-root.mjs'
|
|
6
|
+
import resolveFromProjectRoot, {
|
|
7
|
+
SKIP_CONSUMER_RESOLVE_SPECS,
|
|
8
|
+
} from './resolve-from-project-root.js'
|
|
9
|
+
|
|
10
|
+
describe('resolveFromProjectRoot', () => {
|
|
11
|
+
const kitRoot = resolve(consumerDepFixtureRoot, 'kit')
|
|
12
|
+
const kitUiFile = resolve(consumerDepFixtureRoot, '.wphs/.kit-module-config/ui/ModuleConfigNavContext.tsx')
|
|
13
|
+
const appFile = resolve(consumerDepFixtureRoot, 'src/app.tsx')
|
|
14
|
+
|
|
15
|
+
const plugin = resolveFromProjectRoot(consumerDepFixtureRoot, kitRoot)
|
|
16
|
+
const resolveId = /** @type {(source: string, importer: string) => Promise<string | null>} */ (
|
|
17
|
+
plugin.resolveId.bind(plugin)
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
it('does not force-resolve react for kit UI (avoids CJS index.js in browser)', async () => {
|
|
21
|
+
assert.ok(SKIP_CONSUMER_RESOLVE_SPECS.has('react'))
|
|
22
|
+
assert.equal(await resolveId('react', kitUiFile), null)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('does not force-resolve react/jsx-dev-runtime for kit UI (alias + optimizeDeps)', async () => {
|
|
26
|
+
assert.equal(await resolveId('react/jsx-dev-runtime', kitUiFile), null)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('still resolves other deps from the consumer for kit UI', async () => {
|
|
30
|
+
const resolved = await resolveId('vite', kitUiFile)
|
|
31
|
+
assert.match(resolved ?? '', /node_modules[/\\]vite[/\\]/)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('ignores non-kit importers', async () => {
|
|
35
|
+
assert.equal(await resolveId('vite', appFile), null)
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -64,6 +64,7 @@ export async function initModuleConfigRuntime(): Promise<ModuleConfigState> {
|
|
|
64
64
|
])
|
|
65
65
|
state = buildState(schema, defaults, overrides)
|
|
66
66
|
applyRuntimeSideEffects(state)
|
|
67
|
+
window.dispatchEvent(new CustomEvent(MODULE_CONFIG_CHANGED, { detail: state }))
|
|
67
68
|
return state
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -53,6 +53,7 @@ function ModuleConfigShellInner({
|
|
|
53
53
|
isApplying,
|
|
54
54
|
validationErrors,
|
|
55
55
|
persistenceSource,
|
|
56
|
+
initError,
|
|
56
57
|
setFieldValue,
|
|
57
58
|
applyChanges,
|
|
58
59
|
discardDraft,
|
|
@@ -124,7 +125,11 @@ function ModuleConfigShellInner({
|
|
|
124
125
|
const developerOptionToggleField = state?.schema.find((field) => field.name === 'developer_option')
|
|
125
126
|
|
|
126
127
|
if (!state) {
|
|
127
|
-
return
|
|
128
|
+
return (
|
|
129
|
+
<div className={`p-4 ${hsTypography.helper}`}>
|
|
130
|
+
{initError ?? 'Loading module config…'}
|
|
131
|
+
</div>
|
|
132
|
+
)
|
|
128
133
|
}
|
|
129
134
|
|
|
130
135
|
const onExport = () => {
|
|
@@ -18,6 +18,7 @@ export function useModuleConfig() {
|
|
|
18
18
|
const [validationErrors, setValidationErrors] = useState<Array<ValidationError>>([])
|
|
19
19
|
const [persistenceSource, setPersistenceSource] = useState<'local' | 'example' | 'empty'>('empty')
|
|
20
20
|
const [isApplying, setIsApplying] = useState(false)
|
|
21
|
+
const [initError, setInitError] = useState<string | null>(null)
|
|
21
22
|
|
|
22
23
|
const isDirty =
|
|
23
24
|
JSON.stringify(draftValues) !== JSON.stringify(appliedValues)
|
|
@@ -26,6 +27,45 @@ export function useModuleConfig() {
|
|
|
26
27
|
void loadWorkspaceMeta().then((source) => setPersistenceSource(source ?? 'empty'))
|
|
27
28
|
}, [appliedValues])
|
|
28
29
|
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
let cancelled = false
|
|
32
|
+
|
|
33
|
+
const syncFromRuntime = (next: ModuleConfigState) => {
|
|
34
|
+
if (cancelled) return
|
|
35
|
+
setState(next)
|
|
36
|
+
setDraftValues(next.moduleValues)
|
|
37
|
+
setAppliedValues(next.moduleValues)
|
|
38
|
+
setValidationErrors([])
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const existing = getModuleConfigState()
|
|
42
|
+
if (existing) {
|
|
43
|
+
syncFromRuntime(existing)
|
|
44
|
+
return () => {
|
|
45
|
+
cancelled = true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
void ensureModuleConfigReady()
|
|
50
|
+
.then((ready) => {
|
|
51
|
+
if (ready) syncFromRuntime(ready)
|
|
52
|
+
})
|
|
53
|
+
.catch((error) => {
|
|
54
|
+
console.error('[module-config] Failed to initialize', error)
|
|
55
|
+
if (!cancelled) {
|
|
56
|
+
setInitError(
|
|
57
|
+
error instanceof Error
|
|
58
|
+
? error.message
|
|
59
|
+
: 'Failed to load module config. Check that /fields.json is available.',
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return () => {
|
|
65
|
+
cancelled = true
|
|
66
|
+
}
|
|
67
|
+
}, [])
|
|
68
|
+
|
|
29
69
|
useEffect(() => {
|
|
30
70
|
const onChange = (event: Event) => {
|
|
31
71
|
const detail = (event as CustomEvent<ModuleConfigState>).detail
|
|
@@ -110,6 +150,7 @@ export function useModuleConfig() {
|
|
|
110
150
|
isApplying,
|
|
111
151
|
validationErrors,
|
|
112
152
|
persistenceSource,
|
|
153
|
+
initError,
|
|
113
154
|
setFieldValue,
|
|
114
155
|
applyChanges,
|
|
115
156
|
discardDraft,
|
|
@@ -117,8 +158,9 @@ export function useModuleConfig() {
|
|
|
117
158
|
}
|
|
118
159
|
}
|
|
119
160
|
|
|
120
|
-
export async function ensureModuleConfigReady() {
|
|
161
|
+
export async function ensureModuleConfigReady(): Promise<ModuleConfigState | null> {
|
|
121
162
|
if (!getModuleConfigState()) {
|
|
122
163
|
await initModuleConfigRuntime()
|
|
123
164
|
}
|
|
165
|
+
return getModuleConfigState()
|
|
124
166
|
}
|