@woodsportal/hubspot-kit 1.0.2

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.
Files changed (135) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +62 -0
  4. package/SECURITY.md +27 -0
  5. package/dist/chunk-JDGIAYHX.js +87 -0
  6. package/dist/chunk-JDGIAYHX.js.map +1 -0
  7. package/dist/chunk-U4KFGTEW.js +136 -0
  8. package/dist/chunk-U4KFGTEW.js.map +1 -0
  9. package/dist/cli.js +1849 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/exec-K5C6LZP4.js +10 -0
  12. package/dist/exec-K5C6LZP4.js.map +1 -0
  13. package/dist/index.d.ts +228 -0
  14. package/dist/index.js +204 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/vite/index.d.ts +17 -0
  17. package/dist/vite/index.js +9 -0
  18. package/dist/vite/index.js.map +1 -0
  19. package/examples/README.md +12 -0
  20. package/examples/fixtures/adopted-module-hybrid/public/fields.json +1 -0
  21. package/examples/fixtures/adopted-module-hybrid/public/module.html +1 -0
  22. package/examples/fixtures/adopted-module-hybrid/woodscli.json +7 -0
  23. package/examples/fixtures/adopted-module-monolith/public/fields.json +1 -0
  24. package/examples/fixtures/adopted-module-monolith/woodscli.json +7 -0
  25. package/examples/fixtures/adopted-theme-minimal/src/theme/templates/page.html +1 -0
  26. package/examples/fixtures/adopted-theme-minimal/src/theme/theme.json +1 -0
  27. package/examples/fixtures/adopted-theme-minimal/woodscli.json +7 -0
  28. package/examples/fixtures/existing-module-hybrid/public/fields.json +1 -0
  29. package/examples/fixtures/existing-module-hybrid/public/module.html +1 -0
  30. package/examples/fixtures/existing-theme-minimal/templates/page.html +1 -0
  31. package/examples/fixtures/existing-theme-minimal/theme.json +1 -0
  32. package/examples/greenfield/module-hybrid-cdn/README.md +9 -0
  33. package/examples/greenfield/module-hybrid-cdn/index.html +1 -0
  34. package/examples/greenfield/module-hybrid-cdn/package.json +14 -0
  35. package/examples/greenfield/module-hybrid-cdn/public/fields.json +1 -0
  36. package/examples/greenfield/module-hybrid-cdn/public/module.html +1 -0
  37. package/examples/greenfield/module-hybrid-cdn/src/main.tsx +2 -0
  38. package/examples/greenfield/module-hybrid-cdn/vite.config.dev.mjs +1 -0
  39. package/examples/greenfield/module-hybrid-cdn/vite.config.hubspot.mjs +1 -0
  40. package/examples/greenfield/module-hybrid-cdn/woodscli.json +8 -0
  41. package/examples/greenfield/module-hybrid-cdn/wphs.adapter.ts +7 -0
  42. package/examples/greenfield/module-monolith/package.json +12 -0
  43. package/examples/greenfield/module-monolith/public/fields.json +1 -0
  44. package/examples/greenfield/module-monolith/vite.config.dev.mjs +1 -0
  45. package/examples/greenfield/module-monolith/vite.config.monolith.mjs +1 -0
  46. package/examples/greenfield/module-monolith/woodscli.json +25 -0
  47. package/examples/greenfield/module-monolith/wphs.adapter.ts +7 -0
  48. package/examples/greenfield/theme-starter/package.json +11 -0
  49. package/examples/greenfield/theme-starter/src/theme/css/main.css +1 -0
  50. package/examples/greenfield/theme-starter/src/theme/templates/base.html +1 -0
  51. package/examples/greenfield/theme-starter/src/theme/templates/page.html +1 -0
  52. package/examples/greenfield/theme-starter/src/theme/theme.json +1 -0
  53. package/examples/greenfield/theme-starter/theme.json +6 -0
  54. package/examples/greenfield/theme-starter/vite.config.dev.mjs +1 -0
  55. package/examples/greenfield/theme-starter/woodscli.json +7 -0
  56. package/examples/manifest.json +20 -0
  57. package/examples/smoke/run-matrix.mjs +100 -0
  58. package/package.json +94 -0
  59. package/scripts/audit-module-config-fields.mjs +73 -0
  60. package/scripts/audit-parity.mjs +22 -0
  61. package/scripts/audit-tdz-split.mjs +111 -0
  62. package/scripts/build-cdn.mjs +36 -0
  63. package/scripts/check-hubspot-bundle-size.mjs +58 -0
  64. package/scripts/config-files.mjs +53 -0
  65. package/scripts/detect-layout.mjs +70 -0
  66. package/scripts/ensure-wphs-workspace.mjs +53 -0
  67. package/scripts/generate-cdn-manifest.mjs +92 -0
  68. package/scripts/generate-module-config-example.mjs +57 -0
  69. package/scripts/hubspot-module-postbuild.mjs +151 -0
  70. package/scripts/load-portal-cdn-config.mjs +91 -0
  71. package/scripts/migrate-sdk-3-api.mjs +144 -0
  72. package/scripts/module-config-dir.mjs +12 -0
  73. package/scripts/portal-env-mode.mjs +24 -0
  74. package/scripts/portal-vite-env.mjs +39 -0
  75. package/scripts/project-root.mjs +30 -0
  76. package/scripts/publish-cdn-github.mjs +273 -0
  77. package/scripts/read-woodsportal-config.mjs +40 -0
  78. package/scripts/resolve-cdn-base-url.mjs +32 -0
  79. package/scripts/resolve-consumer-dep.mjs +25 -0
  80. package/scripts/resolve-portal-build-id.mjs +67 -0
  81. package/scripts/run-dev.mjs +93 -0
  82. package/scripts/run-hubspot-module-postbuild.mjs +19 -0
  83. package/scripts/run-vite-build.mjs +33 -0
  84. package/scripts/tailwind/prefix-plugin.js +291 -0
  85. package/scripts/tailwind/prefix.env.js +11 -0
  86. package/scripts/tailwind/tailwind-content-plugin.js +27 -0
  87. package/scripts/tailwind/tailwind-content.js +267 -0
  88. package/scripts/verify-cdn-api-endpoint.mjs +68 -0
  89. package/scripts/vite/ensure-dev-kit-shims.js +49 -0
  90. package/scripts/vite/ensure-dev-module-config-shim.js +1 -0
  91. package/scripts/vite/module-config-store.js +242 -0
  92. package/scripts/vite/plugins.d.ts +9 -0
  93. package/scripts/vite/portal-build-shared.js +110 -0
  94. package/scripts/vite/react-dev-plugin-options.js +21 -0
  95. package/scripts/vite/resolve-from-project-root.js +31 -0
  96. package/scripts/vite/sdk-log-bridge.js +104 -0
  97. package/scripts/watch-hubspot.mjs +86 -0
  98. package/scripts/wphs-paths.mjs +115 -0
  99. package/scripts/write-audit-artifacts.mjs +56 -0
  100. package/templates/hubspot.config.yml.example +10 -0
  101. package/templates/module-hybrid-cdn/README.md +9 -0
  102. package/templates/module-hybrid-cdn/hubspot.config.yml.example +10 -0
  103. package/templates/module-hybrid-cdn/index.html +1 -0
  104. package/templates/module-hybrid-cdn/package.json +14 -0
  105. package/templates/module-hybrid-cdn/public/fields.json +1 -0
  106. package/templates/module-hybrid-cdn/public/module.html +1 -0
  107. package/templates/module-hybrid-cdn/src/main.tsx +2 -0
  108. package/templates/module-hybrid-cdn/vite.config.dev.mjs +1 -0
  109. package/templates/module-hybrid-cdn/vite.config.hubspot.mjs +1 -0
  110. package/templates/module-hybrid-cdn/woodscli.json +8 -0
  111. package/templates/module-hybrid-cdn/wphs.adapter.ts +7 -0
  112. package/templates/module-monolith/hubspot.config.yml.example +10 -0
  113. package/templates/module-monolith/package.json +12 -0
  114. package/templates/module-monolith/public/fields.json +1 -0
  115. package/templates/module-monolith/vite.config.dev.mjs +1 -0
  116. package/templates/module-monolith/vite.config.monolith.mjs +1 -0
  117. package/templates/module-monolith/woodscli.json +25 -0
  118. package/templates/module-monolith/wphs.adapter.ts +7 -0
  119. package/templates/theme-starter/hubspot.config.yml.example +10 -0
  120. package/templates/theme-starter/package.json +11 -0
  121. package/templates/theme-starter/src/theme/css/main.css +1 -0
  122. package/templates/theme-starter/src/theme/templates/base.html +1 -0
  123. package/templates/theme-starter/src/theme/templates/page.html +1 -0
  124. package/templates/theme-starter/src/theme/theme.json +1 -0
  125. package/templates/theme-starter/theme.json +6 -0
  126. package/templates/theme-starter/vite.config.dev.mjs +1 -0
  127. package/templates/theme-starter/woodscli.json +7 -0
  128. package/vite/vite.config.audit.mjs +33 -0
  129. package/vite/vite.config.cdn-app.mjs +44 -0
  130. package/vite/vite.config.cdn-esm.mjs +35 -0
  131. package/vite/vite.config.cdn-vendor.mjs +33 -0
  132. package/vite/vite.config.dev.mjs +62 -0
  133. package/vite/vite.config.hubspot.mjs +33 -0
  134. package/vite/vite.config.monolith.mjs +55 -0
  135. package/vite/vite.config.tdz-audit.mjs +58 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * WoodsCLI workspace (`.wphs/`) — single local home for config, assets, fixtures, cache, audit.
3
+ */
4
+ import { existsSync, readFileSync } from 'node:fs'
5
+ import { join, resolve } from 'node:path'
6
+
7
+ import { findProjectRootWithConfig, resolveProjectConfigPath } from './config-files.mjs'
8
+
9
+ export const WPHS_WORKSPACE_DIR = '.wphs'
10
+
11
+ /** @deprecated use WPHS_WORKSPACE_DIR */
12
+ export const DEFAULT_MODULE_CONFIG_DIR = WPHS_WORKSPACE_DIR
13
+
14
+ const LEGACY_WORKSPACE_DIRS = ['.dev', '.woodsportal']
15
+
16
+ /**
17
+ * @param {string} [projectRoot]
18
+ */
19
+ export function readWphsWorkspaceDir(projectRoot) {
20
+ const root = projectRoot ?? findProjectRootWithConfig()
21
+ const configPath = resolveProjectConfigPath(root)
22
+ if (configPath && existsSync(configPath)) {
23
+ try {
24
+ const raw = JSON.parse(readFileSync(configPath, 'utf8'))
25
+ const dir = raw?.dev?.moduleConfigDir
26
+ if (typeof dir === 'string' && dir.trim()) {
27
+ const trimmed = dir.trim()
28
+ if (trimmed !== WPHS_WORKSPACE_DIR) {
29
+ throw new Error(
30
+ `dev.moduleConfigDir must be "${WPHS_WORKSPACE_DIR}" (got "${trimmed}"). Run wp migrate.`,
31
+ )
32
+ }
33
+ return trimmed
34
+ }
35
+ } catch (error) {
36
+ if (error instanceof Error && error.message.includes('moduleConfigDir')) {
37
+ throw error
38
+ }
39
+ }
40
+ }
41
+ return WPHS_WORKSPACE_DIR
42
+ }
43
+
44
+ /** @deprecated use readWphsWorkspaceDir */
45
+ export const readModuleConfigDir = readWphsWorkspaceDir
46
+
47
+ /**
48
+ * @param {string} projectRoot
49
+ */
50
+ export function wphsPaths(projectRoot) {
51
+ const workspaceDir = readWphsWorkspaceDir(projectRoot)
52
+ const workspaceRoot = resolve(projectRoot, workspaceDir)
53
+ return {
54
+ workspaceDir,
55
+ moduleConfigDir: workspaceDir,
56
+ workspaceRoot,
57
+ devDir: workspaceRoot,
58
+ configDir: join(workspaceRoot, 'config'),
59
+ localConfigPath: join(workspaceRoot, 'config', 'module-config.local.json'),
60
+ exampleConfigPath: join(workspaceRoot, 'config', 'module-config.example.json'),
61
+ assetsDir: join(workspaceRoot, 'assets', 'branding'),
62
+ fixturesDir: join(workspaceRoot, 'fixtures'),
63
+ hubspotDataFixturePath: join(workspaceRoot, 'fixtures', 'hubspot-data.json'),
64
+ previewFixturesDir: join(workspaceRoot, 'fixtures', 'preview'),
65
+ cacheDir: join(workspaceRoot, 'cache'),
66
+ auditDir: join(workspaceRoot, 'audit'),
67
+ baselineDir: join(workspaceRoot, 'audit', 'baseline'),
68
+ stateDir: join(workspaceRoot, 'state'),
69
+ kitModuleConfigLink: join(workspaceRoot, '.kit-module-config'),
70
+ kitBootstrapLink: join(workspaceRoot, '.kit-bootstrap.tsx'),
71
+ readmePath: join(workspaceRoot, 'README.md'),
72
+ brandingAssetsUrlPrefix: `/${workspaceDir}/assets/branding/`,
73
+ legacyBrandingAssetsUrlPrefixes: [
74
+ '/dev/branding-assets/',
75
+ '/.dev/branding-assets/',
76
+ `/${workspaceDir}/branding-assets/`,
77
+ ],
78
+ legacyWorkspaceDirs: LEGACY_WORKSPACE_DIRS,
79
+ }
80
+ }
81
+
82
+ /** @deprecated use wphsPaths */
83
+ export function moduleConfigPaths(projectRoot) {
84
+ const paths = wphsPaths(projectRoot)
85
+ return {
86
+ moduleConfigDir: paths.moduleConfigDir,
87
+ devDir: paths.devDir,
88
+ localConfigPath: paths.localConfigPath,
89
+ exampleConfigPath: paths.exampleConfigPath,
90
+ assetsDir: paths.assetsDir,
91
+ brandingAssetsUrlPrefix: paths.brandingAssetsUrlPrefix,
92
+ legacyBrandingAssetsUrlPrefix: paths.legacyBrandingAssetsUrlPrefixes[0],
93
+ legacyBrandingAssetsUrlPrefixes: paths.legacyBrandingAssetsUrlPrefixes,
94
+ ...paths,
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Subdirectories created by wp doctor / wp init.
100
+ * @param {string} projectRoot
101
+ * @returns {string[]}
102
+ */
103
+ export function wphsWorkspaceSubdirs(projectRoot) {
104
+ const p = wphsPaths(projectRoot)
105
+ return [
106
+ p.configDir,
107
+ p.assetsDir,
108
+ p.fixturesDir,
109
+ p.previewFixturesDir,
110
+ p.cacheDir,
111
+ p.auditDir,
112
+ p.baselineDir,
113
+ p.stateDir,
114
+ ]
115
+ }
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Refresh docs/audit/artifact-sizes.json from current dist outputs.
4
+ */
5
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
6
+ import { resolve, dirname } from 'node:path'
7
+ import { fileURLToPath } from 'node:url'
8
+ import { findProjectRoot } from './project-root.mjs'
9
+ import { gzipSync } from 'node:zlib'
10
+
11
+ const root = findProjectRoot()
12
+ const auditDir = resolve(root, 'docs/audit')
13
+ mkdirSync(auditDir, { recursive: true })
14
+
15
+ const HUBSPOT_LIMIT = 1.5 * 1024 * 1024
16
+
17
+ function measure(path) {
18
+ const raw = readFileSync(path)
19
+ return {
20
+ rawBytes: raw.length,
21
+ gzipBytes: gzipSync(raw).length,
22
+ rawMiB: +(raw.length / (1024 * 1024)).toFixed(3),
23
+ gzipKiB: +(gzipSync(raw).length / 1024).toFixed(1),
24
+ overValidationLimit: raw.length > HUBSPOT_LIMIT,
25
+ }
26
+ }
27
+
28
+ const report = {
29
+ generatedAt: new Date().toISOString(),
30
+ embedMode: process.env.VITE_PORTAL_EMBED_MODE ?? 'cdn',
31
+ hubspotLimits: { validationMiB: 1.5, bufferMiB: 2.0 },
32
+ artifacts: {},
33
+ cdn: {},
34
+ }
35
+
36
+ const moduleDir = resolve(root, 'dist/WoodsPortal.Module')
37
+ for (const name of ['module.js', 'module.css', 'module.html', 'fields.json']) {
38
+ const path = resolve(moduleDir, name)
39
+ if (existsSync(path)) {
40
+ report.artifacts[name] = measure(path)
41
+ }
42
+ }
43
+
44
+ const cdnDir = resolve(root, 'dist/cdn')
45
+ if (existsSync(cdnDir)) {
46
+ for (const file of readdirSync(cdnDir)) {
47
+ if (file.endsWith('.js') || file === 'manifest.json') {
48
+ report.cdn[file] = file.endsWith('.json')
49
+ ? JSON.parse(readFileSync(resolve(cdnDir, file), 'utf8'))
50
+ : measure(resolve(cdnDir, file))
51
+ }
52
+ }
53
+ }
54
+
55
+ writeFileSync(resolve(auditDir, 'artifact-sizes.json'), JSON.stringify(report, null, 2))
56
+ console.log('[audit] wrote docs/audit/artifact-sizes.json')
@@ -0,0 +1,10 @@
1
+ # HubSpot CLI personal access key — copy to hubspot.config.yml (gitignored).
2
+ # Generate at: https://app.hubspot.com/l/personal-access-key
3
+ # Docs: https://developers.hubspot.com/docs/cms/developer-reference/local-development-cli
4
+
5
+ defaultPortal: your-portal-id
6
+ portals:
7
+ - name: dev
8
+ portalId: 12345678
9
+ authType: personalaccesskey
10
+ personalAccessKey: YOUR_PAT_HERE
@@ -0,0 +1,9 @@
1
+ # HubSpot portal module (hybrid CDN)
2
+
3
+ Scaffolded by `wp init --template module-hybrid-cdn`.
4
+
5
+ ```bash
6
+ npm install
7
+ wp doctor
8
+ wp dev
9
+ ```
@@ -0,0 +1,10 @@
1
+ # HubSpot CLI personal access key — copy to hubspot.config.yml (gitignored).
2
+ # Generate at: https://app.hubspot.com/l/personal-access-key
3
+ # Docs: https://developers.hubspot.com/docs/cms/developer-reference/local-development-cli
4
+
5
+ defaultPortal: your-portal-id
6
+ portals:
7
+ - name: staging
8
+ portalId: 12345678
9
+ authType: personalaccesskey
10
+ personalAccessKey: YOUR_PAT_HERE
@@ -0,0 +1 @@
1
+ <!doctype html><html><head><meta charset="UTF-8"/><title>WoodsCLI dev</title></head><body><div id="app"></div><script type="module" src="/src/main.tsx"></script></body></html>
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "my-hubspot-portal-module",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "local": "wp dev",
7
+ "doctor": "wp doctor",
8
+ "build:prod": "wp build --tier prod",
9
+ "deploy:prod": "wp deploy --tier prod"
10
+ },
11
+ "devDependencies": {
12
+ "@woodsportal/hubspot-kit": "^1.0.0"
13
+ }
14
+ }
@@ -0,0 +1 @@
1
+ [{"name":"title","label":"Title","type":"text","default":"WoodsCLI module"}]
@@ -0,0 +1 @@
1
+ <div id="app"></div>
@@ -0,0 +1,2 @@
1
+ import { mountDevPortal } from '@woodsportal/hubspot-kit/dev/bootstrap'
2
+ void mountDevPortal()
@@ -0,0 +1 @@
1
+ export { default } from '@woodsportal/hubspot-kit/vite/vite.config.dev.mjs'
@@ -0,0 +1 @@
1
+ export { default } from '@woodsportal/hubspot-kit/vite/vite.config.hubspot.mjs'
@@ -0,0 +1,8 @@
1
+ {
2
+ "configVersion": 1,
3
+ "projectType": "module-hybrid-cdn",
4
+ "module": {"name": "my-portal-module", "uploadPath": "dw-modules/my-portal-module.module", "outDir": "dist/MyPortal.Module"},
5
+ "cdn": {"mode": "jsdelivr", "buildIdFile": ".portal-build-id", "mirror": "portal.cdn.json"},
6
+ "entries": {"app": "src/cdn/app-entry.ts", "vendor": "src/cdn/vendor-entry.ts", "hubspotBootstrap": "src/hubspot/bootstrap.ts", "localDev": "src/main.tsx"},
7
+ "dev": {"moduleConfigDir": ".wphs", "adapter": "./wphs.adapter.ts", "fieldsJson": "public/fields.json"}
8
+ }
@@ -0,0 +1,7 @@
1
+ import type { HubSpotKitAdapter } from '@woodsportal/hubspot-kit'
2
+ const adapter: HubSpotKitAdapter = {
3
+ syncLiveData(built) {
4
+ ;(window as Window & { __WPHS_DATA__?: Record<string, unknown> }).__WPHS_DATA__ = built
5
+ },
6
+ }
7
+ export default adapter
@@ -0,0 +1,10 @@
1
+ # HubSpot CLI personal access key — copy to hubspot.config.yml (gitignored).
2
+ # Generate at: https://app.hubspot.com/l/personal-access-key
3
+ # Docs: https://developers.hubspot.com/docs/cms/developer-reference/local-development-cli
4
+
5
+ defaultPortal: your-portal-id
6
+ portals:
7
+ - name: staging
8
+ portalId: 12345678
9
+ authType: personalaccesskey
10
+ personalAccessKey: YOUR_PAT_HERE
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "my-hubspot-monolith-module",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "local": "wp dev",
7
+ "build:prod": "wp build --tier prod --hubspot-only"
8
+ },
9
+ "devDependencies": {
10
+ "@woodsportal/hubspot-kit": "^1.0.0"
11
+ }
12
+ }
@@ -0,0 +1 @@
1
+ [{"name":"title","label":"Title","type":"text","default":"WoodsCLI module"}]
@@ -0,0 +1 @@
1
+ export { default } from '@woodsportal/hubspot-kit/vite/vite.config.dev.mjs'
@@ -0,0 +1 @@
1
+ export { default } from '@woodsportal/hubspot-kit/vite/vite.config.monolith.mjs'
@@ -0,0 +1,25 @@
1
+ {
2
+ "configVersion": 1,
3
+ "projectType": "module-monolith",
4
+ "module": {
5
+ "name": "my-portal-module",
6
+ "uploadPath": "dw-modules/my-portal-module.module",
7
+ "outDir": "dist/MyPortal.Module"
8
+ },
9
+ "cdn": {
10
+ "mode": "none",
11
+ "buildIdFile": ".portal-build-id",
12
+ "mirror": "portal.cdn.json"
13
+ },
14
+ "entries": {
15
+ "app": "src/cdn/app-entry.ts",
16
+ "vendor": "src/cdn/vendor-entry.ts",
17
+ "hubspotBootstrap": "src/hubspot/bootstrap.ts",
18
+ "localDev": "src/main.tsx"
19
+ },
20
+ "dev": {
21
+ "moduleConfigDir": ".wphs",
22
+ "adapter": "./wphs.adapter.ts",
23
+ "fieldsJson": "public/fields.json"
24
+ }
25
+ }
@@ -0,0 +1,7 @@
1
+ import type { HubSpotKitAdapter } from '@woodsportal/hubspot-kit'
2
+ const adapter: HubSpotKitAdapter = {
3
+ syncLiveData(built) {
4
+ ;(window as Window & { __WPHS_DATA__?: Record<string, unknown> }).__WPHS_DATA__ = built
5
+ },
6
+ }
7
+ export default adapter
@@ -0,0 +1,10 @@
1
+ # HubSpot CLI personal access key — copy to hubspot.config.yml (gitignored).
2
+ # Generate at: https://app.hubspot.com/l/personal-access-key
3
+ # Docs: https://developers.hubspot.com/docs/cms/developer-reference/local-development-cli
4
+
5
+ defaultPortal: your-portal-id
6
+ portals:
7
+ - name: staging
8
+ portalId: 12345678
9
+ authType: personalaccesskey
10
+ personalAccessKey: YOUR_PAT_HERE
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "my-hubspot-theme",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "doctor": "wp doctor"
7
+ },
8
+ "devDependencies": {
9
+ "@woodsportal/hubspot-kit": "^1.0.0"
10
+ }
11
+ }
@@ -0,0 +1 @@
1
+ body { font-family: system-ui; }
@@ -0,0 +1 @@
1
+ <!doctype html><html><head><link rel="stylesheet" href="../css/main.css"/></head><body>{% block body %}{% endblock %}</body></html>
@@ -0,0 +1 @@
1
+ {% extends "./base.html" %}{% block body %}<h1>WoodsCLI theme</h1>{% endblock %}
@@ -0,0 +1 @@
1
+ {"label":"My Theme","preview_path":"templates/page.html"}
@@ -0,0 +1,6 @@
1
+ {
2
+ "label": "My WoodsPortal Theme",
3
+ "preview_path": "./templates/home.html",
4
+ "enable_domain_stylesheets": false,
5
+ "is_available_for_new_content": true
6
+ }
@@ -0,0 +1 @@
1
+ export { default } from '@woodsportal/hubspot-kit/vite/vite.config.dev.mjs'
@@ -0,0 +1,7 @@
1
+ {
2
+ "configVersion": 1,
3
+ "projectType": "theme-starter",
4
+ "module": {"name": "n/a", "uploadPath": "n/a", "outDir": "dist/n/a"},
5
+ "theme": {"name": "my-theme", "uploadPath": "themes/my-theme", "srcDir": "src/theme", "themeJson": "src/theme/theme.json"},
6
+ "dev": {"moduleConfigDir": ".wphs", "fieldsJson": "public/fields.json"}
7
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Audit-only Vite config: production HubSpot build + rollup visualizer treemap.
3
+ * Usage: vite build --config vite.config.audit.mjs
4
+ */
5
+ import { defineConfig } from 'vite'
6
+ import { visualizer } from 'rollup-plugin-visualizer'
7
+ import { resolve, dirname } from 'node:path'
8
+ import { fileURLToPath } from 'node:url'
9
+ import baseConfigFactory from './vite.config.ts'
10
+
11
+ const __dirname = dirname(fileURLToPath(import.meta.url))
12
+
13
+ const base = baseConfigFactory({ mode: 'production', command: 'build' })
14
+
15
+ export default defineConfig({
16
+ ...base,
17
+ build: {
18
+ ...base.build,
19
+ sourcemap: true,
20
+ rollupOptions: {
21
+ ...base.build?.rollupOptions,
22
+ plugins: [
23
+ visualizer({
24
+ filename: resolve(__dirname, 'docs/audit/bundle-stats.html'),
25
+ gzipSize: true,
26
+ brotliSize: true,
27
+ template: 'treemap',
28
+ json: resolve(__dirname, 'docs/audit/bundle-visualizer.json'),
29
+ }),
30
+ ],
31
+ },
32
+ },
33
+ })
@@ -0,0 +1,44 @@
1
+ import { defineConfig } from 'vite'
2
+ import { resolve } from 'node:path'
3
+ import {
4
+ portalBuildId,
5
+ portalDefine,
6
+ portalPlugins,
7
+ portalResolve,
8
+ root,
9
+ } from '../scripts/vite/portal-build-shared.js'
10
+
11
+ const vendorGlobals = {
12
+ react: 'WoodsPortalVendor.React',
13
+ 'react/jsx-runtime': 'WoodsPortalVendor.jsxRuntime',
14
+ 'react/jsx-dev-runtime': 'WoodsPortalVendor.jsxDevRuntime',
15
+ 'react-dom': 'WoodsPortalVendor.ReactDOM',
16
+ 'react-dom/client': 'WoodsPortalVendor.ReactDOMClient',
17
+ }
18
+
19
+ export default defineConfig(({ mode }) => ({
20
+ plugins: portalPlugins(mode, { codeSplitting: false }),
21
+ resolve: portalResolve(mode),
22
+ define: portalDefine(mode),
23
+ build: {
24
+ outDir: resolve(root, 'dist/cdn'),
25
+ emptyOutDir: false,
26
+ copyPublicDir: false,
27
+ cssCodeSplit: false,
28
+ lib: {
29
+ entry: resolve(root, 'src/cdn/app-entry.ts'),
30
+ name: 'WoodsPortalApp',
31
+ fileName: () => `app.${portalBuildId()}.js`,
32
+ formats: ['iife'],
33
+ },
34
+ rollupOptions: {
35
+ external: Object.keys(vendorGlobals),
36
+ output: {
37
+ globals: vendorGlobals,
38
+ inlineDynamicImports: true,
39
+ assetFileNames: `app.${portalBuildId()}.css`,
40
+ },
41
+ },
42
+ minify: true,
43
+ },
44
+ }))
@@ -0,0 +1,35 @@
1
+ import { defineConfig } from 'vite'
2
+ import { resolve } from 'node:path'
3
+ import {
4
+ portalBuildId,
5
+ portalDefine,
6
+ portalPlugins,
7
+ portalResolve,
8
+ root,
9
+ } from '../scripts/vite/portal-build-shared.js'
10
+
11
+ /** Phase 2: ESM CDN build with route code-splitting (not used for HubSpot module.js). */
12
+ export default defineConfig(({ mode }) => ({
13
+ plugins: portalPlugins(mode, { codeSplitting: true }),
14
+ resolve: portalResolve(mode),
15
+ define: portalDefine(mode),
16
+ build: {
17
+ outDir: resolve(root, 'dist/cdn-esm'),
18
+ emptyOutDir: true,
19
+ copyPublicDir: false,
20
+ cssCodeSplit: true,
21
+ manifest: true,
22
+ rollupOptions: {
23
+ input: {
24
+ app: resolve(root, 'src/cdn/app-entry.ts'),
25
+ },
26
+ output: {
27
+ format: 'es',
28
+ entryFileNames: `assets/[name].${portalBuildId()}.[hash].js`,
29
+ chunkFileNames: `assets/[name].${portalBuildId()}.[hash].js`,
30
+ assetFileNames: `assets/[name].${portalBuildId()}.[hash][extname]`,
31
+ },
32
+ },
33
+ minify: true,
34
+ },
35
+ }))
@@ -0,0 +1,33 @@
1
+ import { defineConfig } from 'vite'
2
+ import { resolve } from 'node:path'
3
+ import {
4
+ portalBuildId,
5
+ portalDefine,
6
+ portalPlugins,
7
+ portalResolve,
8
+ root,
9
+ } from '../scripts/vite/portal-build-shared.js'
10
+
11
+ export default defineConfig(({ mode }) => ({
12
+ plugins: portalPlugins(mode, { codeSplitting: false }),
13
+ resolve: portalResolve(mode),
14
+ define: portalDefine(mode),
15
+ build: {
16
+ outDir: resolve(root, 'dist/cdn'),
17
+ emptyOutDir: true,
18
+ copyPublicDir: false,
19
+ cssCodeSplit: false,
20
+ lib: {
21
+ entry: resolve(root, 'src/cdn/vendor-entry.ts'),
22
+ name: 'WoodsPortalVendor',
23
+ fileName: () => `vendor.${portalBuildId()}.js`,
24
+ formats: ['iife'],
25
+ },
26
+ rollupOptions: {
27
+ output: {
28
+ inlineDynamicImports: true,
29
+ },
30
+ },
31
+ minify: true,
32
+ },
33
+ }))
@@ -0,0 +1,62 @@
1
+ import { defineConfig } from 'vite'
2
+ import viteReact from '@vitejs/plugin-react'
3
+ import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
4
+ import { dirname, resolve } from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
+ import tailwindcss from '@tailwindcss/vite'
7
+
8
+ import tailwindPrefixPlugin from '../scripts/tailwind/prefix-plugin.js'
9
+ import TailwindContentPlugin from '../scripts/tailwind/tailwind-content-plugin.js'
10
+ import sdkLogBridge from '../scripts/vite/sdk-log-bridge.js'
11
+ import moduleConfigStore from '../scripts/vite/module-config-store.js'
12
+ import resolveFromProjectRoot from '../scripts/vite/resolve-from-project-root.js'
13
+ import { createDevReactPluginOptions } from '../scripts/vite/react-dev-plugin-options.js'
14
+ import { ensureDevKitShims } from '../scripts/vite/ensure-dev-kit-shims.js'
15
+ import isPrefix from '../scripts/tailwind/prefix.env.js'
16
+ import { findProjectRoot, getKitRoot } from '../scripts/project-root.mjs'
17
+
18
+ const kitRoot = getKitRoot()
19
+ const projectRoot = findProjectRoot()
20
+ const { moduleConfigRoot, bootstrapShim } = ensureDevKitShims(projectRoot, kitRoot)
21
+
22
+ export default defineConfig(({ mode, command }) => {
23
+ return {
24
+ root: projectRoot,
25
+ plugins: [
26
+ resolveFromProjectRoot(projectRoot, kitRoot),
27
+ ...(command === 'serve' && mode === 'dev'
28
+ ? [sdkLogBridge(), moduleConfigStore(projectRoot)]
29
+ : []),
30
+ TanStackRouterVite({ autoCodeSplitting: false }),
31
+ viteReact(createDevReactPluginOptions()),
32
+ tailwindcss(),
33
+ ...(isPrefix(mode) ? [tailwindPrefixPlugin(), TailwindContentPlugin()] : []),
34
+ ],
35
+ resolve: {
36
+ preserveSymlinks: true,
37
+ alias: {
38
+ '@/dev/module-config': moduleConfigRoot,
39
+ '@woodsportal/hubspot-kit/dev/bootstrap': bootstrapShim,
40
+ '@': resolve(projectRoot, './src'),
41
+ },
42
+ },
43
+ optimizeDeps: {
44
+ exclude: [
45
+ 'woodsportal-client-sdk',
46
+ 'woodsportal-client-sdk/auth',
47
+ 'woodsportal-client-sdk/crm',
48
+ ],
49
+ },
50
+ define: {
51
+ 'process.env.NODE_ENV': JSON.stringify(mode === 'dev' ? 'development' : 'production'),
52
+ 'process.env': {},
53
+ process: JSON.stringify({ env: {} }),
54
+ },
55
+ server: {
56
+ port: 3000,
57
+ fs: {
58
+ allow: [projectRoot, kitRoot],
59
+ },
60
+ },
61
+ }
62
+ })
@@ -0,0 +1,33 @@
1
+ import { defineConfig } from 'vite'
2
+ import { resolve } from 'node:path'
3
+ import {
4
+ portalDefine,
5
+ portalPlugins,
6
+ portalResolve,
7
+ root,
8
+ } from '../scripts/vite/portal-build-shared.js'
9
+
10
+ export default defineConfig(({ mode }) => ({
11
+ plugins: portalPlugins(mode, { codeSplitting: false }),
12
+ resolve: portalResolve(mode),
13
+ define: portalDefine(mode),
14
+ build: {
15
+ outDir: resolve(root, 'dist/WoodsPortal.Module'),
16
+ emptyOutDir: true,
17
+ copyPublicDir: false,
18
+ cssCodeSplit: false,
19
+ lib: {
20
+ entry: resolve(root, 'src/hubspot/bootstrap.ts'),
21
+ name: 'WoodsPortalHubSpotBootstrap',
22
+ fileName: () => 'module.js',
23
+ formats: ['iife'],
24
+ },
25
+ rollupOptions: {
26
+ output: {
27
+ assetFileNames: 'module.css',
28
+ inlineDynamicImports: true,
29
+ },
30
+ },
31
+ minify: true,
32
+ },
33
+ }))