@chidchanun/bcp 0.1.20 → 0.1.21

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # BCP Framework
2
2
 
3
- BCP Framework is a React full-stack framework with file-based routing, SSR, client navigation, API routes, middleware, metadata, client islands, cache/revalidation, security defaults and standalone production builds.
3
+ BCP Framework is a React full-stack framework with file-based routing, SSR, client navigation, API routes, middleware, metadata, client islands, cache/revalidation, validation, structured errors, authentication, database primitives, security defaults and standalone production builds.
4
4
 
5
- > Current release target: `0.1.11`. BCP is still pre-1.0 and validates each release candidate before the manual npm publish step.
5
+ > Current release target: `0.1.21`. BCP is still pre-1.0 and validates each release candidate before the manual npm publish step.
6
6
 
7
7
  ## Quick start
8
8
 
@@ -86,6 +86,30 @@ See [Application Modules](docs/application-modules.md) for the complete boundary
86
86
 
87
87
  Generated Tailwind projects compile to `public/bcp.css`. BCP 0.1.6 inlines that stylesheet into SSR HTML when it is 8 KiB or smaller, removing the stylesheet request from the initial render-critical path. Larger stylesheets remain external so the browser can cache them normally. If the application's Content Security Policy does not allow inline styles, BCP automatically keeps the external stylesheet link.
88
88
 
89
+ ## Development hydration parity
90
+
91
+ BCP 0.1.21 fixes a development-only hydration mismatch where the SSR transform and the React Refresh client transform could assign different semantic values to the same multiline JSX attribute.
92
+
93
+ For example, this is supported application code:
94
+
95
+ ```tsx
96
+ <div
97
+ className="
98
+ min-h-screen
99
+ bg-white
100
+ text-slate-950
101
+ "
102
+ />
103
+ ```
104
+
105
+ BCP 0.1.20 already normalized Windows `CRLF` and standalone `CR` source line endings to `LF`, but Babel's JSX transform could still collapse the multiline quoted attribute to a single-space-separated string while SSR preserved the original line breaks and indentation.
106
+
107
+ In 0.1.21, Babel remains responsible for TypeScript stripping and React Refresh registration, but JSX is preserved until esbuild compiles it with the development JSX runtime. This keeps static JSX attribute semantics aligned between SSR and the development client bundle.
108
+
109
+ Applications should not need to rewrite multiline classes to one line or use `suppressHydrationWarning` to work around framework transform differences. Genuine runtime mismatches caused by values such as `Date.now()`, `Math.random()`, browser-only initial state, locale differences or changing external data still need to be fixed in application code.
110
+
111
+ See [Hydration and deterministic rendering](docs/hydration.md) for the transform pipeline and troubleshooting guidance.
112
+
89
113
  ## Commands
90
114
 
91
115
  ```bash
@@ -117,7 +141,7 @@ bcp update --dry-run
117
141
  Or select a published version/dist-tag explicitly:
118
142
 
119
143
  ```bash
120
- bcp update 0.1.11
144
+ bcp update 0.1.21
121
145
  bcp update next
122
146
  ```
123
147
 
@@ -777,12 +801,19 @@ No real npm publish command is run automatically by the repository.
777
801
  - [Server Data Loaders](docs/server-data-loaders.md)
778
802
  - [Protected Route Guards](docs/route-guards.md)
779
803
  - [Form Actions and Server Mutations](docs/form-actions.md)
804
+ - [Validation](docs/validation.md)
805
+ - [Error Handling](docs/error-handling.md)
806
+ - [Authentication](docs/authentication.md)
807
+ - [Auth Route Guards](docs/auth-route-guards.md)
780
808
  - [JWT Cookie Sessions](docs/session-auth.md)
809
+ - [Database](docs/database.md)
810
+ - [Database Migrations](docs/database-migrations.md)
811
+ - [Middleware](docs/middleware.md)
812
+ - [Hydration and deterministic rendering](docs/hydration.md)
781
813
  - [Updating BCP Framework](docs/updating.md)
782
814
  - [Routing](docs/routing.md)
783
815
  - [Configuration](docs/configuration.md)
784
816
  - [Caching](docs/caching.md)
785
- - [Middleware](docs/middleware.md)
786
817
  - [Security](docs/security.md)
787
818
  - [Deployment](docs/deployment.md)
788
819
  - [Releasing](docs/releasing.md)
package/docs/README.md CHANGED
@@ -4,7 +4,7 @@ This directory is the documentation source of truth for the BCP Framework docume
4
4
 
5
5
  The recommended documentation website project name is `bcp-docs`.
6
6
 
7
- > Documentation target: BCP Framework `0.1.20`
7
+ > Documentation target: BCP Framework `0.1.21`
8
8
 
9
9
  ## Purpose
10
10
 
@@ -63,7 +63,7 @@ The website should not invent API behavior that is not documented or tested in t
63
63
  | Website route | Source file | Description |
64
64
  | --- | --- | --- |
65
65
  | `/docs/middleware` | `middleware.md` | Middleware System v2 and v1 compatibility |
66
- | `/docs/hydration` | `hydration.md` | SSR/client hydration, deterministic rendering and Windows CRLF behavior |
66
+ | `/docs/hydration` | `hydration.md` | SSR/client transform parity, deterministic rendering and Windows line endings |
67
67
  | `/docs/caching` | `caching.md` | Cache and revalidation |
68
68
  | `/docs/security` | `security.md` | Framework security defaults |
69
69
  | `/docs/development-logging` | `development-logging.md` | Development request logging |
@@ -75,9 +75,9 @@ Use the files under `docs/releases/` for release pages.
75
75
  Recommended route format:
76
76
 
77
77
  ```text
78
- /releases/0.1.18
79
78
  /releases/0.1.19
80
79
  /releases/0.1.20
80
+ /releases/0.1.21
81
81
  ```
82
82
 
83
83
  The newest release should also be available from `/releases`.
@@ -97,7 +97,8 @@ Recommended feature groups:
97
97
  - Loading and error UI
98
98
  - API routes
99
99
  - Client islands / partial hydration
100
- - Deterministic development hydration across LF/CRLF source checkouts
100
+ - Deterministic development hydration across server/client transform pipelines
101
+ - LF/CRLF-safe development source handling
101
102
 
102
103
  ### Server data and mutations
103
104
 
@@ -217,9 +218,9 @@ Production
217
218
  Development Logging
218
219
 
219
220
  Releases
221
+ 0.1.21
220
222
  0.1.20
221
223
  0.1.19
222
- 0.1.18
223
224
  ```
224
225
 
225
226
  ## Suggested documentation page layout
@@ -351,7 +352,7 @@ See `validation.md` for the complete API and examples.
351
352
 
352
353
  ## Error Handling documentation priority
353
354
 
354
- BCP 0.1.20 introduces the public `bcp/error` entrypoint and a standard HTTP error envelope.
355
+ BCP 0.1.20 introduced the public `bcp/error` entrypoint and a standard HTTP error envelope.
355
356
 
356
357
  The docs website should clearly distinguish:
357
358
 
@@ -375,17 +376,27 @@ See `error-handling.md` for the complete API and examples.
375
376
 
376
377
  ## Hydration documentation priority
377
378
 
378
- BCP 0.1.20 also fixes a Windows development hydration mismatch caused by CRLF source line endings passing through the React Refresh/Babel transform differently from SSR.
379
+ BCP 0.1.20 added line-ending normalization for the development React Refresh path. That removed the Windows `CRLF` versus `LF` mismatch, but a second issue remained when Babel compiled multiline quoted JSX attributes and collapsed their whitespace differently from SSR.
380
+
381
+ BCP 0.1.21 completes this fix by keeping Babel responsible for TypeScript removal and React Refresh instrumentation while leaving JSX untransformed. esbuild then performs the development JSX transform with the development JSX runtime enabled.
379
382
 
380
383
  The docs website should make these points clear:
381
384
 
382
- - multiline JSX attributes such as template-literal `className` values are supported,
383
- - developers should not need to rewrite them as one-line strings to avoid framework hydration warnings,
384
- - BCP normalizes `CRLF` and standalone `CR` source line endings to `LF` before the development Babel transform,
385
+ - multiline quoted JSX attributes are supported,
386
+ - multiline template-literal JSX expressions are supported,
387
+ - developers should not need to rewrite multiline `className` values as one-line strings to avoid framework hydration warnings,
388
+ - `CRLF` and standalone `CR` source line endings are normalized to `LF` before development instrumentation,
389
+ - React Refresh instrumentation must not change the semantic value of JSX attributes,
385
390
  - the framework fix does not suppress genuine hydration mismatches caused by random values, locale differences, browser-only initial branches, changing external data or invalid HTML,
386
391
  - `suppressHydrationWarning` is not a general-purpose solution.
387
392
 
388
- See `hydration.md` for the full explanation and troubleshooting steps.
393
+ See `hydration.md` for the full explanation, transform pipeline and troubleshooting steps.
394
+
395
+ ## Release roadmap adjustment
396
+
397
+ `0.1.21` is reserved for the hydration parity hotfix because `0.1.20` was already published before the remaining Babel JSX whitespace mismatch was isolated.
398
+
399
+ The previously planned Developer Tools release moves to `0.1.22`, and later roadmap items should shift forward accordingly unless they are regrouped into a larger milestone.
389
400
 
390
401
  ## Release workflow for documentation
391
402
 
package/docs/hydration.md CHANGED
@@ -2,21 +2,21 @@
2
2
 
3
3
  BCP uses server-side rendering for the initial HTML and React hydration in the browser. The server-rendered tree and the first client-rendered tree must produce the same element attributes and text.
4
4
 
5
- ## Windows CRLF support
5
+ ## Development transform parity
6
6
 
7
- BCP Framework 0.1.20 normalizes application source line endings before the development React Refresh/Babel transform.
7
+ BCP Framework 0.1.21 fixes a development hydration mismatch caused by the server and client using different JSX transform semantics.
8
8
 
9
- This fixes a Windows-specific hydration warning that could appear when a JSX attribute used a multiline template literal, for example:
9
+ A common trigger is a multiline quoted JSX attribute:
10
10
 
11
11
  ```tsx
12
12
  export default function Page() {
13
13
  return (
14
14
  <main
15
- className={`
15
+ className="
16
16
  min-h-screen
17
17
  bg-white
18
18
  text-slate-950
19
- `}
19
+ "
20
20
  >
21
21
  Hello
22
22
  </main>
@@ -24,13 +24,63 @@ export default function Page() {
24
24
  }
25
25
  ```
26
26
 
27
- On a CRLF checkout, the development client transform could previously preserve carriage-return characters differently from the SSR transform. React then compared two visually equivalent class lists whose underlying strings were different and reported a hydration mismatch.
27
+ Before 0.1.21, development SSR loaded TSX through the server runtime while the client React Refresh path transformed the same module with `@babel/preset-react`. Babel's JSX transform normalizes whitespace in multiline quoted JSX attributes, so the client could receive a value such as:
28
+
29
+ ```text
30
+ " min-h-screen bg-white text-slate-950 "
31
+ ```
32
+
33
+ while SSR produced the original multiline value:
34
+
35
+ ```text
36
+ "\n min-h-screen\n bg-white\n text-slate-950\n "
37
+ ```
38
+
39
+ Those class lists are visually equivalent to CSS but they are different JavaScript strings, so React reports a hydration mismatch.
40
+
41
+ BCP 0.1.21 keeps Babel in the development pipeline for TypeScript stripping and React Refresh registration, but Babel no longer compiles JSX. JSX is handed to esbuild with the development JSX runtime enabled. This keeps development JSX semantics aligned with the framework's esbuild-based client compilation and avoids Babel rewriting multiline attribute values before hydration.
42
+
43
+ ## Windows CRLF support
44
+
45
+ BCP Framework 0.1.20 added source line-ending normalization for the development React Refresh path.
46
+
47
+ Application source is normalized from `CRLF` (`\r\n`) and standalone `CR` (`\r`) to `LF` (`\n`) before Babel processes development modules. This prevents Windows line endings from introducing carriage-return differences between SSR and the client bundle.
48
+
49
+ The 0.1.20 fix correctly removed carriage-return mismatches, but a separate Babel JSX whitespace normalization issue remained for multiline quoted JSX attributes. That remaining transform-parity issue is addressed by 0.1.21.
50
+
51
+ Developers do not need to rewrite multiline `className` values as one-line strings to work around either framework issue.
28
52
 
29
- BCP now normalizes both `CRLF` (`\r\n`) and standalone `CR` (`\r`) source line endings to `LF` (`\n`) before Babel processes development application modules. Developers do not need to rewrite multiline `className` values as one line to work around this framework issue.
53
+ ## Supported multiline patterns
54
+
55
+ Both of these patterns are valid application code:
56
+
57
+ ```tsx
58
+ <div
59
+ className="
60
+ min-h-screen
61
+ bg-white
62
+ text-slate-950
63
+ "
64
+ />
65
+ ```
66
+
67
+ and:
68
+
69
+ ```tsx
70
+ <div
71
+ className={`
72
+ min-h-screen
73
+ bg-white
74
+ text-slate-950
75
+ `}
76
+ />
77
+ ```
78
+
79
+ BCP should hydrate them deterministically without requiring application-specific whitespace workarounds.
30
80
 
31
81
  ## What BCP fixes automatically
32
82
 
33
- The line-ending fix addresses deterministic source transformation. It does not hide genuine hydration differences caused by application behavior.
83
+ The framework fixes deterministic source-transform differences. It does not hide genuine hydration differences caused by application behavior.
34
84
 
35
85
  BCP applications should still avoid producing different initial values on the server and client from code such as:
36
86
 
@@ -55,6 +105,7 @@ Other common application-level causes include:
55
105
 
56
106
  - locale-dependent formatting that differs between server and browser,
57
107
  - data that changes between SSR and hydration without a serialized snapshot,
108
+ - browser-only state initialized from `localStorage`, `sessionStorage` or `matchMedia`,
58
109
  - invalid HTML nesting,
59
110
  - browser extensions that modify the DOM before React hydrates it.
60
111
 
@@ -91,22 +142,49 @@ export default function BrowserValue() {
91
142
  }
92
143
  ```
93
144
 
94
- ## Development and production
145
+ ## Development pipeline
146
+
147
+ The 0.1.21 development client transform is intentionally split by responsibility:
148
+
149
+ ```text
150
+ application TS/TSX
151
+
152
+ line-ending normalization
153
+
154
+ Babel
155
+ - remove TypeScript syntax
156
+ - inject React Refresh registrations
157
+ - preserve JSX
158
+
159
+ esbuild
160
+ - compile JSX
161
+ - use development JSX runtime
162
+ - bundle application modules
163
+
164
+ React hydration
165
+ ```
166
+
167
+ The key rule is that React Refresh instrumentation must not change the semantic value of JSX attributes compared with SSR.
95
168
 
96
- The Windows CRLF issue was specific to the development React Refresh/Babel path. Production client compilation uses the production esbuild pipeline. The 0.1.20 fix makes development source handling deterministic before Babel so development hydration matches the SSR semantics.
169
+ Production client compilation already uses the esbuild production pipeline and does not use the development React Refresh Babel transform.
97
170
 
98
171
  ## Troubleshooting
99
172
 
100
- If React still reports a hydration mismatch after upgrading to a BCP release containing this fix:
173
+ If React still reports a hydration mismatch after upgrading to a BCP release containing the 0.1.21 fix:
101
174
 
102
175
  1. stop the BCP dev server,
103
176
  2. remove `.bcp-framework/`,
104
177
  3. start `bcp dev` again,
105
- 4. inspect the first differing server/client value in the React hydration warning,
106
- 5. check for request-time, random, locale, browser-only or externally changing values.
178
+ 4. hard-refresh the browser,
179
+ 5. inspect the first differing server/client value in the React hydration warning,
180
+ 6. check for request-time, random, locale, browser-only or externally changing values.
181
+
182
+ For framework diagnostics, compare the initial SSR HTML with the generated development client bundle. If the same static JSX attribute produces different strings, treat it as a framework transform-parity regression.
107
183
 
108
184
  Do not use `suppressHydrationWarning` as a general fix. It should only be used when a difference is intentional and understood.
109
185
 
110
186
  ## Regression coverage
111
187
 
112
- The framework test suite contains a Windows-style CRLF fixture with a multiline JSX `className`. The development client bundle is required to normalize source line endings before the React Refresh Babel transform.
188
+ The framework test suite contains a Windows-style CRLF fixture using the same multiline quoted JSX `className` pattern that exposed the issue in a real BCP application.
189
+
190
+ The regression test extracts the generated `className` value from the development bundle and verifies that its semantic string value still contains the expected line breaks and indentation instead of Babel's collapsed whitespace form.
@@ -0,0 +1,92 @@
1
+ # BCP Framework 0.1.21
2
+
3
+ BCP 0.1.21 is a hydration parity hotfix for development builds.
4
+
5
+ ## Why this release exists
6
+
7
+ BCP 0.1.20 fixed a Windows-specific `CRLF` versus `LF` mismatch in the React Refresh client transform. After that fix, a second development-only mismatch was isolated: Babel's JSX transform could normalize whitespace inside multiline quoted JSX attributes differently from the SSR transform.
8
+
9
+ For example:
10
+
11
+ ```tsx
12
+ <div
13
+ className="
14
+ min-h-screen
15
+ bg-white
16
+ text-slate-950
17
+ "
18
+ />
19
+ ```
20
+
21
+ SSR could preserve the multiline string while the development client bundle produced a collapsed value such as:
22
+
23
+ ```text
24
+ " min-h-screen bg-white text-slate-950 "
25
+ ```
26
+
27
+ React correctly treats those as different attribute strings and reports a hydration mismatch.
28
+
29
+ ## Fix
30
+
31
+ The development client pipeline now separates React Refresh instrumentation from JSX compilation:
32
+
33
+ ```text
34
+ TS/TSX source
35
+ -> normalize line endings
36
+ -> Babel: strip TypeScript + inject React Refresh registrations
37
+ -> preserve JSX
38
+ -> esbuild: compile JSX with the development JSX runtime
39
+ -> client bundle
40
+ ```
41
+
42
+ This prevents `@babel/preset-react` from rewriting multiline JSX attribute whitespace before hydration while keeping Fast Refresh support.
43
+
44
+ ## Highlights
45
+
46
+ - Preserves multiline quoted JSX attribute semantics in development client bundles.
47
+ - Keeps the 0.1.20 `CRLF` / `CR` to `LF` source normalization.
48
+ - Uses esbuild as the development JSX compiler after React Refresh instrumentation.
49
+ - Enables the esbuild development JSX runtime for dev bundles.
50
+ - Adds regression coverage using the same multiline quoted `className` pattern that reproduced the real hydration warning.
51
+ - Regression coverage extracts the generated `className` string and compares its semantic value, rather than only checking that carriage-return characters are absent.
52
+ - No application workaround such as rewriting multiline classes to one line is required.
53
+
54
+ ## Compatibility
55
+
56
+ 0.1.21 does not change the public application API.
57
+
58
+ Existing routes, loaders, guards, actions, middleware, validation, authentication, database APIs and the 0.1.20 Error Handling System continue to work unchanged.
59
+
60
+ The change is limited to development client transformation and hydration parity.
61
+
62
+ ## Local package verification
63
+
64
+ Do not install `.package/bcp` directly into an application for release verification. A direct local-directory install can be linked back to the framework checkout. In that layout, application components may resolve `react` from the application while BCP's SSR renderer resolves `react-dom` from the framework checkout, creating two React instances and causing an `Invalid hook call` before hydration starts.
65
+
66
+ Use the packed release artifact under `.package/artifacts/*.tgz` or the existing package smoke tests instead. A packed tarball is installed as a normal package under the application `node_modules` tree, so the framework's React peer dependencies resolve from the same application installation as the rendered components.
67
+
68
+ A stack trace that mixes paths such as:
69
+
70
+ ```text
71
+ <app>/node_modules/react/...
72
+ <framework-checkout>/node_modules/react-dom/...
73
+ ```
74
+
75
+ indicates a linked local-package test with duplicate React instances, not a hydration failure.
76
+
77
+ ## Upgrade verification
78
+
79
+ After upgrading an application:
80
+
81
+ ```powershell
82
+ Remove-Item -Recurse -Force .bcp-framework -ErrorAction SilentlyContinue
83
+ npm run dev
84
+ ```
85
+
86
+ A multiline static JSX attribute should hydrate without the server/client attribute mismatch that occurred in 0.1.20.
87
+
88
+ If a hydration warning remains after 0.1.21, compare the first differing SSR/client value and check for genuine runtime differences such as `Date.now()`, `Math.random()`, locale formatting, browser-only initial state, changing external data or invalid HTML nesting.
89
+
90
+ ## Roadmap note
91
+
92
+ Because 0.1.21 is used for this hotfix, the previously planned Developer Tools milestone moves to 0.1.22.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chidchanun/bcp",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "BCP Framework - a React full-stack framework with file-based routing, SSR, APIs, middleware, islands, caching and standalone production builds.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -881,6 +881,9 @@ export class DevClientBundler {
881
881
  jsx:
882
882
  "automatic",
883
883
 
884
+ jsxDev:
885
+ true,
886
+
884
887
  define:
885
888
  createClientEnvironmentDefines(
886
889
  "development"
@@ -1010,7 +1013,7 @@ export class DevClientBundler {
1010
1013
  * เปลี่ยนเป็น
1011
1014
  *
1012
1015
  * Page
1013
- * import A
1016
+ * เดิม import A
1014
1017
  * import B
1015
1018
  *
1016
1019
  * จึง rebuild graph ใหม่
@@ -1737,17 +1740,18 @@ function createReactRefreshPlugin(
1737
1740
  extension === ".ts" ||
1738
1741
  extension === ".tsx";
1739
1742
 
1743
+ const parsesJsx =
1744
+ extension !== ".ts";
1745
+
1740
1746
  const presets:
1741
1747
  any[] = [];
1742
1748
 
1743
1749
  /*
1744
- * Babel 8
1745
- *
1746
- * ไม่ใช้:
1747
- *
1748
- * allowDeclareFields
1749
- * allExtensions
1750
- * isTSX
1750
+ * Babel removes TypeScript syntax and
1751
+ * injects React Refresh registrations.
1752
+ * JSX intentionally remains untransformed
1753
+ * so esbuild owns JSX semantics for both
1754
+ * the normal dev bundle and production.
1751
1755
  */
1752
1756
  if (
1753
1757
  isTypeScript
@@ -1757,17 +1761,6 @@ function createReactRefreshPlugin(
1757
1761
  ]);
1758
1762
  }
1759
1763
 
1760
- presets.push([
1761
- presetReact,
1762
- {
1763
- runtime:
1764
- "automatic",
1765
-
1766
- development:
1767
- true,
1768
- },
1769
- ]);
1770
-
1771
1764
  const result =
1772
1765
  await transformAsync(
1773
1766
  source,
@@ -1784,6 +1777,15 @@ function createReactRefreshPlugin(
1784
1777
  sourceType:
1785
1778
  "module",
1786
1779
 
1780
+ parserOpts:
1781
+ parsesJsx
1782
+ ? {
1783
+ plugins: [
1784
+ "jsx",
1785
+ ],
1786
+ }
1787
+ : undefined,
1788
+
1787
1789
  presets,
1788
1790
 
1789
1791
  plugins: [
@@ -1839,7 +1841,7 @@ ${result.code}
1839
1841
  transformed,
1840
1842
 
1841
1843
  loader:
1842
- "js",
1844
+ "jsx",
1843
1845
 
1844
1846
  resolveDir:
1845
1847
  path.dirname(