dinou 1.1.1 → 1.3.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/README.md +216 -1
- package/dinou/asset-require-hook.js +58 -0
- package/dinou/createScopedName.js +8 -0
- package/dinou/render-html.js +30 -11
- package/dinou/server.js +29 -16
- package/dinou/ssg.js +17 -9
- package/eject.js +12 -4
- package/package.json +55 -45
- package/postcss.config.js +6 -0
- package/webpack.config.js +77 -4
package/README.md
CHANGED
|
@@ -46,7 +46,11 @@ dinou main features are:
|
|
|
46
46
|
|
|
47
47
|
- TypeScript or JavaScript
|
|
48
48
|
|
|
49
|
-
- Full control and customization through the command `npm run eject` (`npx dinou eject`)
|
|
49
|
+
- Full control and customization through the command `npm run eject` (`npx dinou eject`)
|
|
50
|
+
|
|
51
|
+
- Support for the use of `.css`, `.module.css`, and `Tailwind.css`
|
|
52
|
+
|
|
53
|
+
- Support for the use of images in your components (`.png`, `.jpeg`, `.jpg`, `.gif`, `.svg`, `.webp`)
|
|
50
54
|
|
|
51
55
|
## Table of contents
|
|
52
56
|
|
|
@@ -96,6 +100,10 @@ dinou main features are:
|
|
|
96
100
|
|
|
97
101
|
- [`.env` file](#env-file)
|
|
98
102
|
|
|
103
|
+
- [Styles (Tailwind.css, .module.css, and .css)](#styles-tailwindcss-modulecss-and-css)
|
|
104
|
+
|
|
105
|
+
- [Images (`.png`, `.jpeg`, `.jpg`, `.gif`, `.svg`, and `.webp`)](#images-png-jpeg-jpg-gif-svg-and-webp)
|
|
106
|
+
|
|
99
107
|
- [How to run a dinou app](#how-to-run-a-dinou-app)
|
|
100
108
|
|
|
101
109
|
- [Eject dinou](#eject-dinou)
|
|
@@ -895,6 +903,209 @@ dinou is ready to manage env vars in the code that runs on the Server side (Serv
|
|
|
895
903
|
MY_VAR=my_value
|
|
896
904
|
```
|
|
897
905
|
|
|
906
|
+
## Styles (Tailwind.css, .module.css, and .css)
|
|
907
|
+
|
|
908
|
+
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:
|
|
909
|
+
|
|
910
|
+
```typescript
|
|
911
|
+
<link href="/styles.css" rel="stylesheet"></link>
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
- Example with client components:
|
|
915
|
+
|
|
916
|
+
```typescript
|
|
917
|
+
// src/layout.tsx
|
|
918
|
+
"use client";
|
|
919
|
+
|
|
920
|
+
import type { ReactNode } from "react";
|
|
921
|
+
import "./global.css";
|
|
922
|
+
|
|
923
|
+
export default function Layout({ children }: { children: ReactNode }) {
|
|
924
|
+
return (
|
|
925
|
+
<html lang="en">
|
|
926
|
+
<head>
|
|
927
|
+
<title>dinou app</title>
|
|
928
|
+
<link rel="icon" type="image/png" href="/favicon.ico" />
|
|
929
|
+
<link
|
|
930
|
+
rel="apple-touch-icon"
|
|
931
|
+
sizes="180x180"
|
|
932
|
+
href="/apple-touch-icon.png"
|
|
933
|
+
/>
|
|
934
|
+
<link
|
|
935
|
+
rel="icon"
|
|
936
|
+
type="image/png"
|
|
937
|
+
sizes="32x32"
|
|
938
|
+
href="/favicon-32x32.png"
|
|
939
|
+
/>
|
|
940
|
+
<link
|
|
941
|
+
rel="icon"
|
|
942
|
+
type="image/png"
|
|
943
|
+
sizes="16x16"
|
|
944
|
+
href="/favicon-16x16.png"
|
|
945
|
+
/>
|
|
946
|
+
<link rel="manifest" href="/site.webmanifest"></link>
|
|
947
|
+
<link href="/styles.css" rel="stylesheet"></link>
|
|
948
|
+
</head>
|
|
949
|
+
<body>{children}</body>
|
|
950
|
+
</html>
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
```css
|
|
956
|
+
/* global.css */
|
|
957
|
+
@import "tailwindcss";
|
|
958
|
+
|
|
959
|
+
.test1 {
|
|
960
|
+
background-color: purple;
|
|
961
|
+
}
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
```typescript
|
|
965
|
+
// src/page.tsx
|
|
966
|
+
"use client";
|
|
967
|
+
|
|
968
|
+
import styles from "./page.module.css";
|
|
969
|
+
|
|
970
|
+
export default function Page() {
|
|
971
|
+
return (
|
|
972
|
+
<div className={`text-red-500 test1 ${styles.test2}`}>hi world!</div>
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
```css
|
|
978
|
+
/* src/page.module.css */
|
|
979
|
+
.test2 {
|
|
980
|
+
text-decoration: underline;
|
|
981
|
+
}
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
```typescript
|
|
985
|
+
// src/css.d.ts
|
|
986
|
+
declare module "*.module.css" {
|
|
987
|
+
const classes: { [key: string]: string };
|
|
988
|
+
export default classes;
|
|
989
|
+
}
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
- The above will produce the text `hi world!` in red, underlined, and with a purple background color.
|
|
993
|
+
|
|
994
|
+
- **Only styles imported under `"use client"` directive will be detected by Webpack 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.
|
|
995
|
+
|
|
996
|
+
- Example with server components:
|
|
997
|
+
|
|
998
|
+
```typescript
|
|
999
|
+
// src/layout.tsx
|
|
1000
|
+
import type { ReactNode } from "react";
|
|
1001
|
+
|
|
1002
|
+
export default async function Layout({ children }: { children: ReactNode }) {
|
|
1003
|
+
return (
|
|
1004
|
+
<html lang="en">
|
|
1005
|
+
<head>
|
|
1006
|
+
<title>dinou app</title>
|
|
1007
|
+
<link rel="icon" type="image/png" href="/favicon.ico" />
|
|
1008
|
+
<link
|
|
1009
|
+
rel="apple-touch-icon"
|
|
1010
|
+
sizes="180x180"
|
|
1011
|
+
href="/apple-touch-icon.png"
|
|
1012
|
+
/>
|
|
1013
|
+
<link
|
|
1014
|
+
rel="icon"
|
|
1015
|
+
type="image/png"
|
|
1016
|
+
sizes="32x32"
|
|
1017
|
+
href="/favicon-32x32.png"
|
|
1018
|
+
/>
|
|
1019
|
+
<link
|
|
1020
|
+
rel="icon"
|
|
1021
|
+
type="image/png"
|
|
1022
|
+
sizes="16x16"
|
|
1023
|
+
href="/favicon-16x16.png"
|
|
1024
|
+
/>
|
|
1025
|
+
<link rel="manifest" href="/site.webmanifest"></link>
|
|
1026
|
+
<link href="/styles.css" rel="stylesheet"></link>
|
|
1027
|
+
</head>
|
|
1028
|
+
<body>{children}</body>
|
|
1029
|
+
</html>
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
```css
|
|
1035
|
+
/* global.css */
|
|
1036
|
+
@import "tailwindcss";
|
|
1037
|
+
|
|
1038
|
+
.test1 {
|
|
1039
|
+
background-color: purple;
|
|
1040
|
+
}
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
```typescript
|
|
1044
|
+
// src/page.tsx
|
|
1045
|
+
import styles from "./page.module.css";
|
|
1046
|
+
|
|
1047
|
+
export default async function Page() {
|
|
1048
|
+
return (
|
|
1049
|
+
<div className={`text-red-500 test1 ${styles.test2}`}>hi world!</div>
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
```
|
|
1053
|
+
|
|
1054
|
+
```css
|
|
1055
|
+
/* src/page.module.css */
|
|
1056
|
+
.test2 {
|
|
1057
|
+
text-decoration: underline;
|
|
1058
|
+
}
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
```typescript
|
|
1062
|
+
// src/css.d.ts
|
|
1063
|
+
declare module "*.module.css" {
|
|
1064
|
+
const classes: { [key: string]: string };
|
|
1065
|
+
export default classes;
|
|
1066
|
+
}
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
```typescript
|
|
1070
|
+
// src/styles.ts
|
|
1071
|
+
"use client"; // <-- This is key.
|
|
1072
|
+
import "./global.css";
|
|
1073
|
+
import "./page.module.css";
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
## Images (`.png`, `.jpeg`, `.jpg`, `.gif`, `.svg`, and `.webp`)
|
|
1077
|
+
|
|
1078
|
+
dinou is ready to support the use of images in your components. Just do:
|
|
1079
|
+
|
|
1080
|
+
```typescript
|
|
1081
|
+
// src/component.tsx
|
|
1082
|
+
"use client";
|
|
1083
|
+
|
|
1084
|
+
import image from "./image.png"; // import the image from where it is located (inside src folder)
|
|
1085
|
+
|
|
1086
|
+
export default function Component() {
|
|
1087
|
+
return <img src={image} alt="image" />;
|
|
1088
|
+
}
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
**Only images imported under `"use client"` directive will be detected by Webpack and generated in `public` folder**. If you use server components, then you must create an additional file (e.g. `images.ts`) with the `"use client"` directive and import there the images too:
|
|
1092
|
+
|
|
1093
|
+
```typescript
|
|
1094
|
+
// src/images.ts
|
|
1095
|
+
"use client";
|
|
1096
|
+
|
|
1097
|
+
import "./image.png";
|
|
1098
|
+
```
|
|
1099
|
+
|
|
1100
|
+
```typescript
|
|
1101
|
+
// src/component.tsx
|
|
1102
|
+
import image from "./image.png"; // import the image from where it is located (inside src folder)
|
|
1103
|
+
|
|
1104
|
+
export default async function Component() {
|
|
1105
|
+
return <img src={image} alt="image" />;
|
|
1106
|
+
}
|
|
1107
|
+
```
|
|
1108
|
+
|
|
898
1109
|
## How to run a dinou app
|
|
899
1110
|
|
|
900
1111
|
Run `npm run dev` (or `npx dinou dev`) to start the dinou app in development mode. Wait for the logs of Webpack and `Listening on port <port>` to load the page on your browser.
|
|
@@ -908,3 +1119,7 @@ Run `npm run build` (or `npx dinou build`) to build the app and `npm start` (or
|
|
|
908
1119
|
## License
|
|
909
1120
|
|
|
910
1121
|
dinou is licensed under the [MIT License](https://github.com/roggc/dinou/blob/master/LICENSE.md).
|
|
1122
|
+
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
var fs = require("fs");
|
|
2
|
+
var path = require("path");
|
|
3
|
+
var interpolateName = require("loader-utils").interpolateName;
|
|
4
|
+
|
|
5
|
+
function compiler(name, options) {
|
|
6
|
+
return function compile(file) {
|
|
7
|
+
var content = fs.readFileSync(file);
|
|
8
|
+
var context = { resourcePath: file };
|
|
9
|
+
|
|
10
|
+
var resolvedName;
|
|
11
|
+
if (typeof name === "function") {
|
|
12
|
+
var localName = path.basename(file, path.extname(file));
|
|
13
|
+
resolvedName = name(localName, file);
|
|
14
|
+
} else {
|
|
15
|
+
resolvedName = name;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var result = interpolateName(context, resolvedName, {
|
|
19
|
+
content: content,
|
|
20
|
+
regExp: options.regExp,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (options.publicPath) {
|
|
24
|
+
result =
|
|
25
|
+
typeof options.publicPath === "function"
|
|
26
|
+
? options.publicPath(result)
|
|
27
|
+
: options.publicPath + result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function hook(extension, compile) {
|
|
35
|
+
require.extensions[extension] = function (module, file) {
|
|
36
|
+
try {
|
|
37
|
+
const url = compile(file);
|
|
38
|
+
module._compile("module.exports = " + JSON.stringify(url), file);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.error("Error processing file", file, err);
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function addHook(opts) {
|
|
47
|
+
opts = opts || {};
|
|
48
|
+
var extensions = (opts.extensions || []).map(function (ext) {
|
|
49
|
+
return ext.replace(".", "");
|
|
50
|
+
});
|
|
51
|
+
var comp = compiler(opts.name, opts);
|
|
52
|
+
|
|
53
|
+
extensions.forEach(function (ext) {
|
|
54
|
+
hook("." + ext, comp);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = addHook;
|
package/dinou/render-html.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
require("
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
],
|
|
7
|
-
plugins: ["@babel/plugin-transform-modules-commonjs"],
|
|
1
|
+
const addHook = require("./asset-require-hook.js");
|
|
2
|
+
const { register } = require("esbuild-register/dist/node");
|
|
3
|
+
register({
|
|
4
|
+
target: "esnext",
|
|
5
|
+
format: "cjs",
|
|
8
6
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
9
7
|
});
|
|
8
|
+
const createScopedName = require("./createScopedName");
|
|
9
|
+
require("css-modules-require-hook")({
|
|
10
|
+
generateScopedName: createScopedName,
|
|
11
|
+
});
|
|
12
|
+
addHook({
|
|
13
|
+
extensions: ["png", "jpg", "jpeg", "gif", "svg", "webp"],
|
|
14
|
+
name: function (localName, filepath) {
|
|
15
|
+
const result = createScopedName(localName, filepath);
|
|
16
|
+
return result + ".[ext]";
|
|
17
|
+
},
|
|
18
|
+
publicPath: "images/",
|
|
19
|
+
});
|
|
20
|
+
|
|
10
21
|
const { renderToPipeableStream } = require("react-dom/server");
|
|
11
22
|
const { getJSX, getSSGJSX } = require("./get-jsx");
|
|
12
23
|
const { renderJSXToClientJSX } = require("./render-jsx-to-client-jsx");
|
|
@@ -26,6 +37,7 @@ async function renderToStream() {
|
|
|
26
37
|
onError(error) {
|
|
27
38
|
console.error("Render error:", error);
|
|
28
39
|
process.stderr.write(JSON.stringify({ error: error.message }));
|
|
40
|
+
process.exit(1);
|
|
29
41
|
},
|
|
30
42
|
onShellReady() {
|
|
31
43
|
stream.pipe(process.stdout);
|
|
@@ -38,9 +50,16 @@ async function renderToStream() {
|
|
|
38
50
|
}
|
|
39
51
|
}
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
renderToStream();
|
|
43
|
-
} catch (error) {
|
|
53
|
+
process.on("uncaughtException", (error) => {
|
|
44
54
|
process.stderr.write(JSON.stringify({ error: error.message }));
|
|
45
55
|
process.exit(1);
|
|
46
|
-
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
process.on("unhandledRejection", (reason) => {
|
|
59
|
+
process.stderr.write(
|
|
60
|
+
JSON.stringify({ error: reason.message || "Unhandled promise rejection" })
|
|
61
|
+
);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
renderToStream();
|
package/dinou/server.js
CHANGED
|
@@ -1,27 +1,35 @@
|
|
|
1
1
|
require("dotenv/config");
|
|
2
|
-
const
|
|
2
|
+
const webpackRegister = require("react-server-dom-webpack/node-register");
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const { readFileSync } = require("fs");
|
|
5
5
|
const { renderToPipeableStream } = require("react-server-dom-webpack/server");
|
|
6
6
|
const express = require("express");
|
|
7
7
|
const { spawn } = require("child_process");
|
|
8
|
-
const
|
|
8
|
+
const { register } = require("esbuild-register/dist/node");
|
|
9
9
|
const webpack = require("webpack");
|
|
10
10
|
const webpackDevMiddleware = require("webpack-dev-middleware");
|
|
11
11
|
const webpackHotMiddleware = require("webpack-hot-middleware");
|
|
12
12
|
const webpackConfig = require(path.resolve(__dirname, "../webpack.config.js"));
|
|
13
13
|
const { getSSGJSXOrJSX } = require("./get-jsx.js");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
["@babel/preset-react", { runtime: "automatic" }],
|
|
20
|
-
"@babel/preset-typescript",
|
|
21
|
-
],
|
|
22
|
-
plugins: ["@babel/transform-modules-commonjs"],
|
|
14
|
+
const addHook = require("./asset-require-hook.js");
|
|
15
|
+
webpackRegister();
|
|
16
|
+
register({
|
|
17
|
+
target: "esnext",
|
|
18
|
+
format: "cjs",
|
|
23
19
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
24
20
|
});
|
|
21
|
+
const createScopedName = require("./createScopedName");
|
|
22
|
+
require("css-modules-require-hook")({
|
|
23
|
+
generateScopedName: createScopedName,
|
|
24
|
+
});
|
|
25
|
+
addHook({
|
|
26
|
+
extensions: ["png", "jpg", "jpeg", "gif", "svg", "webp"],
|
|
27
|
+
name: function (localName, filepath) {
|
|
28
|
+
const result = createScopedName(localName, filepath);
|
|
29
|
+
return result + ".[ext]";
|
|
30
|
+
},
|
|
31
|
+
publicPath: "images/",
|
|
32
|
+
});
|
|
25
33
|
|
|
26
34
|
const app = express();
|
|
27
35
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
@@ -70,22 +78,27 @@ function renderAppToHtml(reqPath, paramsString) {
|
|
|
70
78
|
|
|
71
79
|
let errorOutput = "";
|
|
72
80
|
child.stderr.on("data", (data) => {
|
|
73
|
-
errorOutput += data;
|
|
81
|
+
errorOutput += data.toString();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
child.on("error", (error) => {
|
|
85
|
+
reject(new Error(`Failed to start child process: ${error.message}`));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
child.on("spawn", () => {
|
|
89
|
+
resolve(child.stdout);
|
|
74
90
|
});
|
|
75
91
|
|
|
76
92
|
child.on("close", (code) => {
|
|
77
93
|
if (code !== 0) {
|
|
78
94
|
try {
|
|
79
95
|
const errorResult = JSON.parse(errorOutput);
|
|
80
|
-
reject(new Error(errorResult.error));
|
|
96
|
+
reject(new Error(errorResult.error || errorOutput));
|
|
81
97
|
} catch {
|
|
82
98
|
reject(new Error(`Child process failed: ${errorOutput}`));
|
|
83
99
|
}
|
|
84
100
|
}
|
|
85
101
|
});
|
|
86
|
-
|
|
87
|
-
// Resolve the stream from the child process
|
|
88
|
-
resolve(child.stdout);
|
|
89
102
|
});
|
|
90
103
|
}
|
|
91
104
|
|
package/dinou/ssg.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
const
|
|
1
|
+
const { register } = require("esbuild-register/dist/node");
|
|
2
2
|
const { buildStaticPages } = require("./build-static-pages");
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
["@babel/preset-react", { runtime: "automatic" }],
|
|
8
|
-
"@babel/preset-typescript",
|
|
9
|
-
],
|
|
10
|
-
plugins: ["@babel/transform-modules-commonjs"],
|
|
3
|
+
const addHook = require("./asset-require-hook.js");
|
|
4
|
+
register({
|
|
5
|
+
target: "esnext",
|
|
6
|
+
format: "cjs",
|
|
11
7
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
12
8
|
});
|
|
9
|
+
const createScopedName = require("./createScopedName");
|
|
10
|
+
require("css-modules-require-hook")({
|
|
11
|
+
generateScopedName: createScopedName,
|
|
12
|
+
});
|
|
13
|
+
addHook({
|
|
14
|
+
extensions: ["png", "jpg", "jpeg", "gif", "svg", "webp"],
|
|
15
|
+
name: function (localName, filepath) {
|
|
16
|
+
const result = createScopedName(localName, filepath);
|
|
17
|
+
return result + ".[ext]";
|
|
18
|
+
},
|
|
19
|
+
publicPath: "images/",
|
|
20
|
+
});
|
|
13
21
|
|
|
14
22
|
(async () => await buildStaticPages())();
|
package/eject.js
CHANGED
|
@@ -16,10 +16,18 @@ if (fs.existsSync(path.join(modulePath, "webpack.config.js"))) {
|
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
fs.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
19
|
+
if (fs.existsSync(path.join(modulePath, "postcss.config.js"))) {
|
|
20
|
+
fs.copyFileSync(
|
|
21
|
+
path.join(modulePath, "postcss.config.js"),
|
|
22
|
+
path.join(projectRoot, "postcss.config.js")
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// don't copy the LICENSE.md file, as it is not needed in the project root
|
|
27
|
+
// fs.copyFileSync(
|
|
28
|
+
// path.join(modulePath, "LICENSE.md"),
|
|
29
|
+
// path.join(projectRoot, "dinou/LICENSE.md")
|
|
30
|
+
// );
|
|
23
31
|
|
|
24
32
|
const pkg = require(path.join(projectRoot, "package.json"));
|
|
25
33
|
pkg.scripts.dev =
|
package/package.json
CHANGED
|
@@ -1,45 +1,55 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dinou",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Minimal React 19 Framework",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"dinou": "./cli.js"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
-
},
|
|
12
|
-
"keywords": [
|
|
13
|
-
"React 19",
|
|
14
|
-
"Framework"
|
|
15
|
-
],
|
|
16
|
-
"author": "Roger Gomez Castells (@roggc)",
|
|
17
|
-
"license": "MIT",
|
|
18
|
-
"repository": {
|
|
19
|
-
"type": "git",
|
|
20
|
-
"url": "https://github.com/roggc/dinou.git"
|
|
21
|
-
},
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"@babel/core": "^7.27.1",
|
|
24
|
-
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
|
25
|
-
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
|
|
26
|
-
"@babel/preset-react": "^7.27.1",
|
|
27
|
-
"@babel/preset-typescript": "^7.27.1",
|
|
28
|
-
"@
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "dinou",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Minimal React 19 Framework",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"dinou": "./cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"React 19",
|
|
14
|
+
"Framework"
|
|
15
|
+
],
|
|
16
|
+
"author": "Roger Gomez Castells (@roggc)",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/roggc/dinou.git"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@babel/core": "^7.27.1",
|
|
24
|
+
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
|
25
|
+
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
|
|
26
|
+
"@babel/preset-react": "^7.27.1",
|
|
27
|
+
"@babel/preset-typescript": "^7.27.1",
|
|
28
|
+
"@tailwindcss/postcss": "^4.1.10",
|
|
29
|
+
"autoprefixer": "^10.4.21",
|
|
30
|
+
"babel-loader": "^10.0.0",
|
|
31
|
+
"commander": "^14.0.0",
|
|
32
|
+
"copy-webpack-plugin": "^13.0.0",
|
|
33
|
+
"cross-env": "^7.0.3",
|
|
34
|
+
"css-loader": "^7.1.2",
|
|
35
|
+
"css-modules-require-hook": "^4.2.3",
|
|
36
|
+
"dotenv": "^16.5.0",
|
|
37
|
+
"esbuild-register": "^3.6.0",
|
|
38
|
+
"express": "^5.1.0",
|
|
39
|
+
"generic-names": "^4.0.0",
|
|
40
|
+
"loader-utils": "^3.3.1",
|
|
41
|
+
"mini-css-extract-plugin": "^2.9.2",
|
|
42
|
+
"postcss": "^8.5.5",
|
|
43
|
+
"postcss-loader": "^8.1.1",
|
|
44
|
+
"react-server-dom-webpack": "^19.1.0",
|
|
45
|
+
"tailwindcss": "^4.1.10",
|
|
46
|
+
"webpack": "^5.99.8",
|
|
47
|
+
"webpack-cli": "^6.0.1",
|
|
48
|
+
"webpack-dev-middleware": "^7.4.2",
|
|
49
|
+
"webpack-hot-middleware": "^2.26.1"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": "^19.1.0",
|
|
53
|
+
"react-dom": "^19.1.0"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/webpack.config.js
CHANGED
|
@@ -3,15 +3,19 @@ const path = require("path");
|
|
|
3
3
|
const ReactServerWebpackPlugin = require("react-server-dom-webpack/plugin");
|
|
4
4
|
const webpack = require("webpack");
|
|
5
5
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
6
|
+
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
|
7
|
+
const createScopedName = require("./dinou/createScopedName");
|
|
6
8
|
|
|
7
9
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
8
10
|
|
|
9
11
|
module.exports = {
|
|
10
12
|
mode: isDevelopment ? "development" : "production",
|
|
11
|
-
entry:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
entry: {
|
|
14
|
+
main: [
|
|
15
|
+
isDevelopment && "webpack-hot-middleware/client?reload=true",
|
|
16
|
+
path.resolve(__dirname, "./dinou/client.jsx"),
|
|
17
|
+
].filter(Boolean),
|
|
18
|
+
},
|
|
15
19
|
output: {
|
|
16
20
|
path: path.resolve(process.cwd(), "./public"),
|
|
17
21
|
filename: "main.js",
|
|
@@ -37,6 +41,60 @@ module.exports = {
|
|
|
37
41
|
},
|
|
38
42
|
exclude: [/node_modules\/(?!dinou)/, /dist/],
|
|
39
43
|
},
|
|
44
|
+
{
|
|
45
|
+
test: /\.module\.css$/,
|
|
46
|
+
use: [
|
|
47
|
+
MiniCssExtractPlugin.loader,
|
|
48
|
+
{
|
|
49
|
+
loader: "css-loader",
|
|
50
|
+
options: {
|
|
51
|
+
modules: {
|
|
52
|
+
getLocalIdent: (context, localIdentName, localName) => {
|
|
53
|
+
return createScopedName(localName, context.resourcePath);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
importLoaders: 1,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
"postcss-loader",
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
test: /\.css$/,
|
|
64
|
+
exclude: /\.module\.css$/,
|
|
65
|
+
use: [
|
|
66
|
+
MiniCssExtractPlugin.loader,
|
|
67
|
+
"css-loader",
|
|
68
|
+
{
|
|
69
|
+
loader: "postcss-loader",
|
|
70
|
+
options: {
|
|
71
|
+
postcssOptions: {
|
|
72
|
+
config: path.resolve(__dirname, "postcss.config.js"),
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
test: /\.(png|jpe?g|gif|svg|webp)$/i,
|
|
80
|
+
type: "asset/resource",
|
|
81
|
+
generator: {
|
|
82
|
+
filename: (pathData) => {
|
|
83
|
+
const resourcePath =
|
|
84
|
+
pathData.module.resourceResolveData?.path ||
|
|
85
|
+
pathData.module.resource;
|
|
86
|
+
|
|
87
|
+
const base = path.basename(
|
|
88
|
+
resourcePath,
|
|
89
|
+
path.extname(resourcePath)
|
|
90
|
+
);
|
|
91
|
+
const scoped = createScopedName(base, resourcePath);
|
|
92
|
+
|
|
93
|
+
return `images/${scoped}[ext]`;
|
|
94
|
+
},
|
|
95
|
+
publicPath: "/",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
40
98
|
],
|
|
41
99
|
},
|
|
42
100
|
plugins: [
|
|
@@ -51,8 +109,23 @@ module.exports = {
|
|
|
51
109
|
},
|
|
52
110
|
],
|
|
53
111
|
}),
|
|
112
|
+
new MiniCssExtractPlugin({
|
|
113
|
+
filename: "[name].css",
|
|
114
|
+
}),
|
|
54
115
|
].filter(Boolean),
|
|
55
116
|
resolve: {
|
|
56
117
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
57
118
|
},
|
|
119
|
+
optimization: {
|
|
120
|
+
splitChunks: {
|
|
121
|
+
cacheGroups: {
|
|
122
|
+
styles: {
|
|
123
|
+
name: "styles",
|
|
124
|
+
type: "css/mini-extract",
|
|
125
|
+
chunks: "all",
|
|
126
|
+
enforce: true,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
58
131
|
};
|