dinou 2.3.3 → 2.4.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 +11 -0
- package/README.md +120 -173
- package/cli.js +7 -6
- package/dinou/core/babel-esm-loader.js +100 -0
- package/dinou/{babel-esm-loader.js → core/get-abs-path-with-ext.js} +4 -95
- package/{react-refresh → dinou/react-refresh}/react-refresh-wrap-modules.js +0 -1
- package/{rollup-plugins → dinou/rollup-plugins}/dinou-asset-plugin.js +2 -2
- package/{rollup-plugins → dinou/rollup-plugins}/rollup-plugin-react-client-manifest.js +122 -40
- package/{rollup.config.js → dinou/rollup.config.js} +8 -8
- package/eject.js +7 -32
- package/package.json +13 -4
- /package/dinou/{asset-extensions.js → core/asset-extensions.js} +0 -0
- /package/dinou/{asset-require-hook.js → core/asset-require-hook.js} +0 -0
- /package/dinou/{build-static-pages.js → core/build-static-pages.js} +0 -0
- /package/dinou/{client-error.jsx → core/client-error.jsx} +0 -0
- /package/dinou/{client.jsx → core/client.jsx} +0 -0
- /package/dinou/{createScopedName.js → core/createScopedName.js} +0 -0
- /package/dinou/{generate-static-page.js → core/generate-static-page.js} +0 -0
- /package/dinou/{generate-static-pages.js → core/generate-static-pages.js} +0 -0
- /package/dinou/{generate-static-rsc.js → core/generate-static-rsc.js} +0 -0
- /package/dinou/{generate-static-rscs.js → core/generate-static-rscs.js} +0 -0
- /package/dinou/{generate-static.js → core/generate-static.js} +0 -0
- /package/dinou/{get-error-jsx.js → core/get-error-jsx.js} +0 -0
- /package/dinou/{get-file-path-and-dynamic-params.js → core/get-file-path-and-dynamic-params.js} +0 -0
- /package/dinou/{get-jsx.js → core/get-jsx.js} +0 -0
- /package/dinou/{get-ssg-jsx-or-jsx.js → core/get-ssg-jsx-or-jsx.js} +0 -0
- /package/dinou/{get-ssg-jsx.js → core/get-ssg-jsx.js} +0 -0
- /package/dinou/{get-static-paths.js → core/get-static-paths.js} +0 -0
- /package/dinou/{import-module.js → core/import-module.js} +0 -0
- /package/dinou/{register-loader.mjs → core/register-loader.mjs} +0 -0
- /package/dinou/{register-paths.js → core/register-paths.js} +0 -0
- /package/dinou/{render-app-to-html.js → core/render-app-to-html.js} +0 -0
- /package/dinou/{render-html.js → core/render-html.js} +0 -0
- /package/dinou/{render-jsx-to-client-jsx.js → core/render-jsx-to-client-jsx.js} +0 -0
- /package/dinou/{revalidating.js → core/revalidating.js} +0 -0
- /package/dinou/{server-function-proxy.js → core/server-function-proxy.js} +0 -0
- /package/dinou/{server.js → core/server.js} +0 -0
- /package/{postcss.config.js → dinou/postcss.config.js} +0 -0
- /package/{react-refresh → dinou/react-refresh}/esm-hmr/client.js +0 -0
- /package/{react-refresh → dinou/react-refresh}/esm-hmr/server.js +0 -0
- /package/{react-refresh → dinou/react-refresh}/is-react-refresh-boundary.js +0 -0
- /package/{react-refresh → dinou/react-refresh}/react-refresh-entry.js +0 -0
- /package/{react-refresh → dinou/react-refresh}/react-refresh-runtime.js +0 -0
- /package/{react-refresh → dinou/react-refresh}/rollup-plugin-esm-hmr.js +0 -0
- /package/{rollup-plugins → dinou/rollup-plugins}/rollup-plugin-server-functions.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [2.4.0]
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- rollup-plugin-react-client-manifest: now emits assets and csss correctly for server components.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Now all folders and files ejected are grouped in dinou folder. What was before dinou folder now is dinou/core folder.
|
|
17
|
+
- README.md, updated.
|
|
18
|
+
|
|
8
19
|
## [2.3.3]
|
|
9
20
|
|
|
10
21
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# **
|
|
1
|
+
# **Dinou**: **A React 19 Framework**
|
|
2
2
|
|
|
3
|
-
[**
|
|
3
|
+
[**Dinou**](https://dinou.dev) is a **React 19 framework**. "dinou" means 19 in Catalan. You can create a Dinou [app](https://github.com/roggc/dinou-app) by running the command **`npx create-dinou@latest my-app`**.
|
|
4
4
|
|
|
5
5
|
Or you can create one by yourself with the following steps:
|
|
6
6
|
|
|
@@ -30,9 +30,9 @@ Or you can create one by yourself with the following steps:
|
|
|
30
30
|
|
|
31
31
|
- Run `npm run dev` (or `npx dinou dev`) to see the page in action in your browser.
|
|
32
32
|
|
|
33
|
-
- If you run `npm run eject` (or `npx dinou eject`),
|
|
33
|
+
- If you run `npm run eject` (or `npx dinou eject`), Dinou will be ejected and copied to your root project folder, so you can customize it.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Dinou main features are:
|
|
36
36
|
|
|
37
37
|
- File-based routing system.
|
|
38
38
|
|
|
@@ -54,7 +54,7 @@ dinou main features are:
|
|
|
54
54
|
|
|
55
55
|
- Support for the use of an import alias in `tsconfig.json` or `jsconfig.json` file.
|
|
56
56
|
|
|
57
|
-
- Error handling with `error.tsx` pages,
|
|
57
|
+
- Error handling with `error.tsx` pages, differentiating behaviour in production and in development.
|
|
58
58
|
|
|
59
59
|
## Table of contents
|
|
60
60
|
|
|
@@ -72,6 +72,8 @@ dinou main features are:
|
|
|
72
72
|
|
|
73
73
|
- [Client Components](#client-components)
|
|
74
74
|
|
|
75
|
+
- [Server Functions](#server-functions)
|
|
76
|
+
|
|
75
77
|
- [Dynamic Parameters (`params` prop)](#dynamic-parameters-params-prop)
|
|
76
78
|
|
|
77
79
|
- [Query Parameters (`query` prop)](#query-parameters-query-prop)
|
|
@@ -114,9 +116,9 @@ dinou main features are:
|
|
|
114
116
|
|
|
115
117
|
- [Import alias (e.g. `"@/..."`)](#import-alias-eg-)
|
|
116
118
|
|
|
117
|
-
- [How to run a
|
|
119
|
+
- [How to run a Dinou app](#how-to-run-a-dinou-app)
|
|
118
120
|
|
|
119
|
-
- [Eject
|
|
121
|
+
- [Eject Dinou](#eject-dinou)
|
|
120
122
|
|
|
121
123
|
- [🚀 Deployment](#-deployment)
|
|
122
124
|
|
|
@@ -148,8 +150,11 @@ dinou main features are:
|
|
|
148
150
|
|
|
149
151
|
```typescript
|
|
150
152
|
// src/dynamic/[name]/page_functions.ts
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
export async function getProps(
|
|
154
|
+
params: { name: string },
|
|
155
|
+
query: Record<string, string>,
|
|
156
|
+
cookies: Record<string, string>
|
|
157
|
+
) {
|
|
153
158
|
const data = await new Promise<string>((r) =>
|
|
154
159
|
setTimeout(() => r(`Hello ${params.name}`), 2000)
|
|
155
160
|
);
|
|
@@ -162,8 +167,11 @@ dinou main features are:
|
|
|
162
167
|
|
|
163
168
|
```typescript
|
|
164
169
|
// src/dynamic/[name]/page_functions.ts
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
export async function getProps(
|
|
171
|
+
params: { name: string },
|
|
172
|
+
query: Record<string, string>,
|
|
173
|
+
cookies: Record<string, string>
|
|
174
|
+
) {
|
|
167
175
|
const data = await new Promise<string>((r) =>
|
|
168
176
|
setTimeout(() => r(`Hello ${params.name}`), 2000)
|
|
169
177
|
);
|
|
@@ -196,11 +204,10 @@ dinou main features are:
|
|
|
196
204
|
|
|
197
205
|
- We have already seen that data can be fetched on the server with the `getProps` function or within the body of a Server Component, but this needs to be accompanied of a mechanism of SSG of the page/s to not increase the FCP.
|
|
198
206
|
|
|
199
|
-
- There is an alternative that do not increase FCP even when rendering dynamically and that is to use `Suspense` for data fetching, either in the server and in the client.
|
|
207
|
+
- There is an alternative that do not increase FCP even when rendering dynamically and that is to use `Suspense` for data fetching, either in the server (in a Server Component) and in the client (in a Client Component).
|
|
200
208
|
|
|
201
209
|
```typescript
|
|
202
210
|
// src/posts/post.tsx
|
|
203
|
-
|
|
204
211
|
"use client";
|
|
205
212
|
|
|
206
213
|
export type PostType = {
|
|
@@ -220,7 +227,6 @@ dinou main features are:
|
|
|
220
227
|
|
|
221
228
|
```typescript
|
|
222
229
|
// src/posts/get-post.tsx
|
|
223
|
-
|
|
224
230
|
"use server";
|
|
225
231
|
|
|
226
232
|
import Post from "./post";
|
|
@@ -240,36 +246,41 @@ dinou main features are:
|
|
|
240
246
|
|
|
241
247
|
```typescript
|
|
242
248
|
// src/posts/page.tsx
|
|
243
|
-
|
|
244
249
|
"use client";
|
|
245
250
|
|
|
246
|
-
import
|
|
251
|
+
import Suspense from "react-enhanced-suspense";
|
|
247
252
|
import { getPost } from "./get-post";
|
|
248
|
-
import Post from "./post";
|
|
249
|
-
import type { PostType } from "./post";
|
|
250
253
|
|
|
251
|
-
export default function Page(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
() =>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
254
|
+
export default function Page() {
|
|
255
|
+
return (
|
|
256
|
+
<>
|
|
257
|
+
<Suspense fallback={<div>Loading...</div>} resourceId="get-post">
|
|
258
|
+
{() => getPost()}
|
|
259
|
+
</Suspense>
|
|
260
|
+
</>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
259
264
|
|
|
260
|
-
|
|
261
|
-
|
|
265
|
+
- In Client Components, the `resourceId` prop together with passing a function to the `children` prop of `Suspense` from `react-enhanced-suspense` makes the promise returned by the Server Function stable between re-renders, and it is only reinvoked the Server Function whenever the `resourceId` changes.
|
|
266
|
+
|
|
267
|
+
- The same can be done with `page.tsx` being a Server Component. In that case we would not use the `resourceId` prop and we will call directly the Server Function:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// src/posts/page.tsx
|
|
271
|
+
import Suspense from "react-enhanced-suspense";
|
|
272
|
+
import { getPost } from "./get-post";
|
|
262
273
|
|
|
274
|
+
export default async function Page({ data }: { data: string }) {
|
|
263
275
|
return (
|
|
264
276
|
<>
|
|
265
277
|
<Suspense fallback={<div>Loading...</div>}>{getPost()}</Suspense>
|
|
266
|
-
<Suspense fallback={<div>Loading2...</div>}>{getPost2()}</Suspense>
|
|
267
278
|
</>
|
|
268
279
|
);
|
|
269
280
|
}
|
|
270
281
|
```
|
|
271
282
|
|
|
272
|
-
-
|
|
283
|
+
- `Suspense` from [react-enhanced-suspense](https://www.npmjs.com/package/react-enhanced-suspense) is React's `Suspense` when no extra prop is used.
|
|
273
284
|
|
|
274
285
|
## Fetching data in the server without `Suspense` (revisited)
|
|
275
286
|
|
|
@@ -285,7 +296,6 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
285
296
|
|
|
286
297
|
```typescript
|
|
287
298
|
// src/catch-all-optional/[[..names]]/page.tsx
|
|
288
|
-
|
|
289
299
|
"use client";
|
|
290
300
|
|
|
291
301
|
export default function Page({
|
|
@@ -306,8 +316,11 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
306
316
|
|
|
307
317
|
```typescript
|
|
308
318
|
// src/catch-all-optional/[[..names]]/page_functions.ts
|
|
309
|
-
|
|
310
|
-
|
|
319
|
+
export async function getProps(
|
|
320
|
+
params: { names: string[] },
|
|
321
|
+
query: Record<string, string>,
|
|
322
|
+
cookies: Record<string, string>
|
|
323
|
+
) {
|
|
311
324
|
const data = await new Promise<string>((r) =>
|
|
312
325
|
setTimeout(() => r(`Hello ${params.names.join(",")}`), 2000)
|
|
313
326
|
);
|
|
@@ -328,7 +341,6 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
328
341
|
|
|
329
342
|
```typescript
|
|
330
343
|
// src/catch-all/[...names]/page.tsx
|
|
331
|
-
|
|
332
344
|
"use client";
|
|
333
345
|
|
|
334
346
|
export default function Page({
|
|
@@ -349,8 +361,11 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
349
361
|
|
|
350
362
|
```typescript
|
|
351
363
|
// src/catch-all/[...names]/page_functions.ts
|
|
352
|
-
|
|
353
|
-
|
|
364
|
+
export async function getProps(
|
|
365
|
+
params: { names: string[] },
|
|
366
|
+
query: Record<string, string>,
|
|
367
|
+
cookies: Record<string, string>
|
|
368
|
+
) {
|
|
354
369
|
const data = await new Promise<string>((r) =>
|
|
355
370
|
setTimeout(() => r(`Hello ${params.names.join(",")}`), 2000)
|
|
356
371
|
);
|
|
@@ -371,7 +386,6 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
371
386
|
|
|
372
387
|
```typescript
|
|
373
388
|
// src/optional/[[name]]/page.tsx
|
|
374
|
-
|
|
375
389
|
"use client";
|
|
376
390
|
|
|
377
391
|
export default function Page({
|
|
@@ -392,8 +406,11 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
392
406
|
|
|
393
407
|
```typescript
|
|
394
408
|
// src/optional/[[name]]/page_functions.ts
|
|
395
|
-
|
|
396
|
-
|
|
409
|
+
export async function getProps(
|
|
410
|
+
params: { name: string },
|
|
411
|
+
query: Record<string, string>,
|
|
412
|
+
cookies: Record<string, string>
|
|
413
|
+
) {
|
|
397
414
|
const data = await new Promise<string>((r) =>
|
|
398
415
|
setTimeout(() => r(`Hello ${params.name ?? ""}`), 2000)
|
|
399
416
|
);
|
|
@@ -414,7 +431,6 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
414
431
|
|
|
415
432
|
```typescript
|
|
416
433
|
// src/dynamic/[name]/page.tsx
|
|
417
|
-
|
|
418
434
|
"use client";
|
|
419
435
|
|
|
420
436
|
export default function Page({
|
|
@@ -435,8 +451,11 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
435
451
|
|
|
436
452
|
```typescript
|
|
437
453
|
// src/dynamic/[name]/page_functions.ts
|
|
438
|
-
|
|
439
|
-
|
|
454
|
+
export async function getProps(
|
|
455
|
+
params: { name: string },
|
|
456
|
+
query: Record<string, string>,
|
|
457
|
+
cookies: Record<string, string>
|
|
458
|
+
) {
|
|
440
459
|
const data = await new Promise<string>((r) =>
|
|
441
460
|
setTimeout(() => r(`Hello ${params.name}`), 2000)
|
|
442
461
|
);
|
|
@@ -457,7 +476,6 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
457
476
|
|
|
458
477
|
```typescript
|
|
459
478
|
// src/static/page.tsx
|
|
460
|
-
|
|
461
479
|
"use client";
|
|
462
480
|
|
|
463
481
|
export default function Page({ data }: { data: string }) {
|
|
@@ -467,8 +485,11 @@ Pages in **dynamic routes** (e.g. `/[id]`, or `/[[id]]`, `[...id]`, `[[...id]]`)
|
|
|
467
485
|
|
|
468
486
|
```typescript
|
|
469
487
|
// src/static/page_functions.ts
|
|
470
|
-
|
|
471
|
-
|
|
488
|
+
export async function getProps(
|
|
489
|
+
params: Record<string, string>,
|
|
490
|
+
query: Record<string, string>,
|
|
491
|
+
cookies: Record<string, string>
|
|
492
|
+
) {
|
|
472
493
|
const data = await new Promise<string>((r) =>
|
|
473
494
|
setTimeout(() => r(`data`), 2000)
|
|
474
495
|
);
|
|
@@ -504,7 +525,11 @@ The framework supports a `page_functions.ts` (or `.tsx`, `.jsx`, `.js`) file in
|
|
|
504
525
|
return ["1", "2", "3"];
|
|
505
526
|
}
|
|
506
527
|
|
|
507
|
-
export async function getProps(
|
|
528
|
+
export async function getProps(
|
|
529
|
+
params: { id: string },
|
|
530
|
+
query: Record<string, string>,
|
|
531
|
+
cookies: Record<string, string>
|
|
532
|
+
) {
|
|
508
533
|
// Fetch data based on the 'id' parameter
|
|
509
534
|
const post = await fetch(`https://api.example.com/posts/${params.id}`).then(
|
|
510
535
|
(res) => res.json()
|
|
@@ -590,7 +615,23 @@ The framework supports a `page_functions.ts` (or `.tsx`, `.jsx`, `.js`) file in
|
|
|
590
615
|
|
|
591
616
|
## Client Components
|
|
592
617
|
|
|
593
|
-
- Client
|
|
618
|
+
- Client Components need to have the directive `"use client";` at the top of the file if they are not imported in other Client Components. That's the case of pages for example, that they are not imported directly in another Client Component. So when defining pages as Client Components **remember to use the directive `"use client";`**. The same applies for layouts, not found pages and error pages. In general, to avoid surprises, is a good practice to put the directive `"use client";` in all Client Components.
|
|
619
|
+
|
|
620
|
+
## Server Functions
|
|
621
|
+
|
|
622
|
+
- Server Functions are functions executed in the server. To define a Server Function use the directive `"use server";` at the top of the file where you define the Server Function. **Server Functions** can be invoked from either a Server Component or a Client Component and **can return Client Components**.
|
|
623
|
+
|
|
624
|
+
- You can access the `req` and `res` objects from express in the Server Function by adding an extra parameter in the definition, the last one:
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
"use server";
|
|
628
|
+
|
|
629
|
+
export async function doSomething(myParam, { req, res }) {
|
|
630
|
+
// ...
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
- In the previous example, the Server Function should be called only with `myParam` as argument. The last argument with references to `req` and `res` from `express` is added by Dinou.
|
|
594
635
|
|
|
595
636
|
## Dynamic Parameters (`params` prop)
|
|
596
637
|
|
|
@@ -820,7 +861,7 @@ The routing system is file-based and supports static routes, dynamic routes, opt
|
|
|
820
861
|
return (
|
|
821
862
|
<html lang="en">
|
|
822
863
|
<head>
|
|
823
|
-
<title>
|
|
864
|
+
<title>Dinou app</title>
|
|
824
865
|
</head>
|
|
825
866
|
<body>
|
|
826
867
|
{sidebar}
|
|
@@ -933,7 +974,7 @@ export default function Layout({ children }: { children: ReactNode }) {
|
|
|
933
974
|
return (
|
|
934
975
|
<html lang="en">
|
|
935
976
|
<head>
|
|
936
|
-
<title>
|
|
977
|
+
<title>Dinou app</title>
|
|
937
978
|
<link rel="icon" type="image/png" href="/favicon.ico" />
|
|
938
979
|
<link
|
|
939
980
|
rel="apple-touch-icon"
|
|
@@ -964,7 +1005,7 @@ Then you will have your favicon in your web app.
|
|
|
964
1005
|
|
|
965
1006
|
## `.env` file
|
|
966
1007
|
|
|
967
|
-
|
|
1008
|
+
Dinou is ready to manage env vars in the code that runs on the Server side (Server Functions, Server Components, and `getProps` function). Create an `.env` file in your project (and add it to your `.gitignore` file to not expose sensitive data to the public) and define there your env variables:
|
|
968
1009
|
|
|
969
1010
|
```bash
|
|
970
1011
|
# .env
|
|
@@ -974,26 +1015,26 @@ MY_VAR=my_value
|
|
|
974
1015
|
|
|
975
1016
|
## Styles (Tailwind.css, .module.css, and .css)
|
|
976
1017
|
|
|
977
|
-
|
|
1018
|
+
Dinou is ready to use Tailwind.css, `.module.css`, and `.css` styles. All styles will be generated in a file in `public` folder named `styles.css`. So you must include this in your `page.tsx` or `layout.tsx` file, in the `head` tag:
|
|
978
1019
|
|
|
979
1020
|
```typescript
|
|
980
1021
|
<link href="/styles.css" rel="stylesheet"></link>
|
|
981
1022
|
```
|
|
982
1023
|
|
|
983
|
-
- Example with
|
|
1024
|
+
- Example with Client Components (is the same for Server Components):
|
|
984
1025
|
|
|
985
1026
|
```typescript
|
|
986
1027
|
// src/layout.tsx
|
|
987
1028
|
"use client";
|
|
988
1029
|
|
|
989
1030
|
import type { ReactNode } from "react";
|
|
990
|
-
import "./
|
|
1031
|
+
import "./globals.css";
|
|
991
1032
|
|
|
992
1033
|
export default function Layout({ children }: { children: ReactNode }) {
|
|
993
1034
|
return (
|
|
994
1035
|
<html lang="en">
|
|
995
1036
|
<head>
|
|
996
|
-
<title>
|
|
1037
|
+
<title>Dinou app</title>
|
|
997
1038
|
<link rel="icon" type="image/png" href="/favicon.ico" />
|
|
998
1039
|
<link
|
|
999
1040
|
rel="apple-touch-icon"
|
|
@@ -1022,7 +1063,7 @@ dinou is ready to use Tailwind.css, `.module.css`, and `.css` styles. All styles
|
|
|
1022
1063
|
```
|
|
1023
1064
|
|
|
1024
1065
|
```css
|
|
1025
|
-
/*
|
|
1066
|
+
/* src/globals.css */
|
|
1026
1067
|
@import "tailwindcss";
|
|
1027
1068
|
|
|
1028
1069
|
.test1 {
|
|
@@ -1060,91 +1101,9 @@ dinou is ready to use Tailwind.css, `.module.css`, and `.css` styles. All styles
|
|
|
1060
1101
|
|
|
1061
1102
|
- The above will produce the text `hi world!` in red, underlined, and with a purple background color.
|
|
1062
1103
|
|
|
1063
|
-
- **Only styles imported under `"use client"` directive will be detected by dinou and generated in a `styles.css` in `public` folder**. This means that if you want to use server components instead of client components, then you must create an additional file (e.g. `styles.ts`) where you use the `"use client"` directive and import all the `.css` files used in server components.
|
|
1064
|
-
|
|
1065
|
-
- Example with server components:
|
|
1066
|
-
|
|
1067
|
-
```typescript
|
|
1068
|
-
// src/layout.tsx
|
|
1069
|
-
import type { ReactNode } from "react";
|
|
1070
|
-
|
|
1071
|
-
export default async function Layout({ children }: { children: ReactNode }) {
|
|
1072
|
-
return (
|
|
1073
|
-
<html lang="en">
|
|
1074
|
-
<head>
|
|
1075
|
-
<title>dinou app</title>
|
|
1076
|
-
<link rel="icon" type="image/png" href="/favicon.ico" />
|
|
1077
|
-
<link
|
|
1078
|
-
rel="apple-touch-icon"
|
|
1079
|
-
sizes="180x180"
|
|
1080
|
-
href="/apple-touch-icon.png"
|
|
1081
|
-
/>
|
|
1082
|
-
<link
|
|
1083
|
-
rel="icon"
|
|
1084
|
-
type="image/png"
|
|
1085
|
-
sizes="32x32"
|
|
1086
|
-
href="/favicon-32x32.png"
|
|
1087
|
-
/>
|
|
1088
|
-
<link
|
|
1089
|
-
rel="icon"
|
|
1090
|
-
type="image/png"
|
|
1091
|
-
sizes="16x16"
|
|
1092
|
-
href="/favicon-16x16.png"
|
|
1093
|
-
/>
|
|
1094
|
-
<link rel="manifest" href="/site.webmanifest"></link>
|
|
1095
|
-
<link href="/styles.css" rel="stylesheet"></link>
|
|
1096
|
-
</head>
|
|
1097
|
-
<body>{children}</body>
|
|
1098
|
-
</html>
|
|
1099
|
-
);
|
|
1100
|
-
}
|
|
1101
|
-
```
|
|
1102
|
-
|
|
1103
|
-
```css
|
|
1104
|
-
/* global.css */
|
|
1105
|
-
@import "tailwindcss";
|
|
1106
|
-
|
|
1107
|
-
.test1 {
|
|
1108
|
-
background-color: purple;
|
|
1109
|
-
}
|
|
1110
|
-
```
|
|
1111
|
-
|
|
1112
|
-
```typescript
|
|
1113
|
-
// src/page.tsx
|
|
1114
|
-
import styles from "./page.module.css";
|
|
1115
|
-
|
|
1116
|
-
export default async function Page() {
|
|
1117
|
-
return (
|
|
1118
|
-
<div className={`text-red-500 test1 ${styles.test2}`}>hi world!</div>
|
|
1119
|
-
);
|
|
1120
|
-
}
|
|
1121
|
-
```
|
|
1122
|
-
|
|
1123
|
-
```css
|
|
1124
|
-
/* src/page.module.css */
|
|
1125
|
-
.test2 {
|
|
1126
|
-
text-decoration: underline;
|
|
1127
|
-
}
|
|
1128
|
-
```
|
|
1129
|
-
|
|
1130
|
-
```typescript
|
|
1131
|
-
// src/css.d.ts
|
|
1132
|
-
declare module "*.module.css" {
|
|
1133
|
-
const classes: { [key: string]: string };
|
|
1134
|
-
export default classes;
|
|
1135
|
-
}
|
|
1136
|
-
```
|
|
1137
|
-
|
|
1138
|
-
```typescript
|
|
1139
|
-
// src/styles.ts
|
|
1140
|
-
"use client"; // <-- This is key.
|
|
1141
|
-
import "./global.css";
|
|
1142
|
-
import "./page.module.css";
|
|
1143
|
-
```
|
|
1144
|
-
|
|
1145
1104
|
## Assets or media files (image, video, and sound)
|
|
1146
1105
|
|
|
1147
|
-
|
|
1106
|
+
Dinou supports the use of assets in your components. Supported file extensions are: `.png`, `.jpeg`, `.jpg`, `.gif`, `.svg`, `.webp`, `.avif`, `.ico`, `.mp4`, `.webm`, `.ogg`, `.mov`, `.avi`, `.mkv`, `.mp3`, `.wav`, `.flac`, `.m4a`, `.aac`, `.mjpeg`, and `.mjpg`.
|
|
1148
1107
|
|
|
1149
1108
|
To use an asset in your component just import it as a default import:
|
|
1150
1109
|
|
|
@@ -1159,23 +1118,7 @@ export default function Component() {
|
|
|
1159
1118
|
}
|
|
1160
1119
|
```
|
|
1161
1120
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
```typescript
|
|
1165
|
-
// src/assets.ts
|
|
1166
|
-
"use client";
|
|
1167
|
-
|
|
1168
|
-
import "./image.png";
|
|
1169
|
-
```
|
|
1170
|
-
|
|
1171
|
-
```typescript
|
|
1172
|
-
// src/component.tsx
|
|
1173
|
-
import image from "./image.png"; // import the image from where it is located (inside src folder)
|
|
1174
|
-
|
|
1175
|
-
export default async function Component() {
|
|
1176
|
-
return <img src={image} alt="image" />;
|
|
1177
|
-
}
|
|
1178
|
-
```
|
|
1121
|
+
Works the same for Server Components.
|
|
1179
1122
|
|
|
1180
1123
|
For typescript, you should create a declaration file like this:
|
|
1181
1124
|
|
|
@@ -1199,57 +1142,61 @@ declare module "*.png" {
|
|
|
1199
1142
|
// and continue with the rest of supported file extensions
|
|
1200
1143
|
```
|
|
1201
1144
|
|
|
1202
|
-
If you miss a certain file extension you can eject and customize
|
|
1145
|
+
If you miss a certain file extension you can eject and customize Dinou to meet your requirements. Just eject and add the extension in this place: `dinou/core/asset-extensions.js`. Just look for the place were all the extensions are mentioned and add yours in this file.
|
|
1203
1146
|
|
|
1204
1147
|
## Import alias (e.g. `"@/..."`)
|
|
1205
1148
|
|
|
1206
|
-
|
|
1149
|
+
Dinou is ready to support import alias, as `import some from "@/..."`. If you want to use them just define the options in `tsconfig.json`:
|
|
1207
1150
|
|
|
1208
1151
|
```json
|
|
1209
|
-
// tsconfig.json
|
|
1152
|
+
// tsconfig.json for a js project
|
|
1210
1153
|
{
|
|
1211
1154
|
"compilerOptions": {
|
|
1212
|
-
// other options
|
|
1213
1155
|
"baseUrl": ".",
|
|
1214
1156
|
"paths": {
|
|
1215
1157
|
"@/*": ["src/*"]
|
|
1216
|
-
}
|
|
1158
|
+
},
|
|
1159
|
+
"allowJs": true,
|
|
1160
|
+
"noEmit": true
|
|
1217
1161
|
},
|
|
1218
|
-
"include": ["src
|
|
1219
|
-
// other configuration fields
|
|
1162
|
+
"include": ["src"]
|
|
1220
1163
|
}
|
|
1221
1164
|
```
|
|
1222
1165
|
|
|
1223
1166
|
```json
|
|
1224
|
-
//
|
|
1167
|
+
// tsconfig.json for a ts project
|
|
1225
1168
|
{
|
|
1226
1169
|
"compilerOptions": {
|
|
1227
1170
|
"baseUrl": ".",
|
|
1228
1171
|
"paths": {
|
|
1229
1172
|
"@/*": ["src/*"]
|
|
1230
|
-
}
|
|
1173
|
+
},
|
|
1174
|
+
"allowJs": true,
|
|
1175
|
+
"noEmit": true,
|
|
1176
|
+
"jsx": "react-jsx",
|
|
1177
|
+
"strict": true
|
|
1231
1178
|
},
|
|
1232
1179
|
"include": ["src"]
|
|
1233
1180
|
}
|
|
1234
1181
|
```
|
|
1235
1182
|
|
|
1236
|
-
## How to run a
|
|
1183
|
+
## How to run a Dinou app
|
|
1237
1184
|
|
|
1238
|
-
Run `npm run dev` (or `npx dinou dev`) to start the
|
|
1185
|
+
Run `npm run dev` (or `npx dinou dev`) to start the Dinou app in development mode. Wait for the logs of the bundler (`waiting for changes...`) and the server (`Listening on port 3000`) to load the page on your browser. In development, the bundler will emit its files in `public` folder.
|
|
1239
1186
|
|
|
1240
1187
|
Run `npm run build` (or `npx dinou build`) to build the app and `npm start` (or `npx dinou start`) to run it. In production, the bundler will emit its files in `dist3` folder.
|
|
1241
1188
|
|
|
1242
|
-
## Eject
|
|
1189
|
+
## Eject Dinou
|
|
1243
1190
|
|
|
1244
|
-
- You can eject
|
|
1191
|
+
- You can eject Dinou with the command `npm run eject` (or `npx dinou eject`). This will copy the files defining Dinou in the root folder of the project (grouped in a `dinou` folder). You will have full control and customization capabilities.
|
|
1245
1192
|
|
|
1246
1193
|
## 🚀 Deployment
|
|
1247
1194
|
|
|
1248
|
-
Projects built with **
|
|
1195
|
+
Projects built with **Dinou** can be deployed to any platform that supports Node.js with custom flags.
|
|
1249
1196
|
|
|
1250
1197
|
### ✅ Recommended: DigitalOcean App Platform
|
|
1251
1198
|
|
|
1252
|
-
|
|
1199
|
+
Dinou works seamlessly on [DigitalOcean App Platform](https://www.digitalocean.com/products/app-platform). You can deploy your project easily without needing any special configuration.
|
|
1253
1200
|
|
|
1254
1201
|
**Why it works well:**
|
|
1255
1202
|
|
|
@@ -1261,9 +1208,9 @@ dinou works seamlessly on [DigitalOcean App Platform](https://www.digitalocean.c
|
|
|
1261
1208
|
|
|
1262
1209
|
### ❌ Not supported: Netlify
|
|
1263
1210
|
|
|
1264
|
-
At the moment, **Netlify is not compatible with
|
|
1211
|
+
At the moment, **Netlify is not compatible with Dinou, because it does not allow passing the `--conditions react-server` flag when starting a Node.js app**. This flag is essential for the app to work.
|
|
1265
1212
|
|
|
1266
|
-
If Netlify adds support for custom runtime flags in the future,
|
|
1213
|
+
If Netlify adds support for custom runtime flags in the future, Dinou compatibility might become possible.
|
|
1267
1214
|
|
|
1268
1215
|
### 🛠 Other Platforms
|
|
1269
1216
|
|
|
@@ -1277,4 +1224,4 @@ For a detailed list of changes, enhancements, and bug fixes across versions, see
|
|
|
1277
1224
|
|
|
1278
1225
|
## License
|
|
1279
1226
|
|
|
1280
|
-
|
|
1227
|
+
Dinou is licensed under the [MIT License](https://github.com/roggc/dinou/blob/master/LICENSE.md).
|
package/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ const path = require("path");
|
|
|
6
6
|
const { pathToFileURL } = require("url");
|
|
7
7
|
|
|
8
8
|
const dinouPath = path.resolve(__dirname, "dinou");
|
|
9
|
+
const corePath = path.resolve(dinouPath, "core");
|
|
9
10
|
const projectRoot = process.cwd();
|
|
10
11
|
|
|
11
12
|
const runCommand = (command, options = {}) => {
|
|
@@ -23,10 +24,10 @@ program
|
|
|
23
24
|
.action(() => {
|
|
24
25
|
console.log("Starting...");
|
|
25
26
|
const startExpress = `node --conditions react-server --import ${
|
|
26
|
-
pathToFileURL(path.join(
|
|
27
|
-
} ${path.join(
|
|
27
|
+
pathToFileURL(path.join(corePath, "register-loader.mjs")).href
|
|
28
|
+
} ${path.join(corePath, "server.js")}`;
|
|
28
29
|
const startDevServer = `cross-env NODE_ENV=development rollup -c ${path.join(
|
|
29
|
-
|
|
30
|
+
dinouPath,
|
|
30
31
|
"rollup.config.js"
|
|
31
32
|
)} -w`;
|
|
32
33
|
runCommand(`npx concurrently "${startExpress}" "${startDevServer}"`);
|
|
@@ -37,7 +38,7 @@ program
|
|
|
37
38
|
.description("Builds the app for production")
|
|
38
39
|
.action(() => {
|
|
39
40
|
console.log("Building the app...");
|
|
40
|
-
const configPath = path.join(
|
|
41
|
+
const configPath = path.join(dinouPath, "rollup.config.js");
|
|
41
42
|
runCommand(`cross-env NODE_ENV=production npx rollup -c ${configPath}`);
|
|
42
43
|
});
|
|
43
44
|
|
|
@@ -48,8 +49,8 @@ program
|
|
|
48
49
|
console.log("Starting the app...");
|
|
49
50
|
runCommand(
|
|
50
51
|
`cross-env NODE_ENV=production node --conditions react-server --import ${
|
|
51
|
-
pathToFileURL(path.join(
|
|
52
|
-
} ${path.join(
|
|
52
|
+
pathToFileURL(path.join(corePath, "register-loader.mjs")).href
|
|
53
|
+
} ${path.join(corePath, "server.js")}`
|
|
53
54
|
);
|
|
54
55
|
});
|
|
55
56
|
|