dinou 1.2.0 → 1.3.1
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 +41 -2
- package/dinou/asset-require-hook.js +58 -0
- package/dinou/render-html.js +22 -4
- package/dinou/server.js +19 -8
- package/dinou/ssg.js +9 -3
- package/eject.js +5 -4
- package/package.json +55 -54
- package/webpack.config.js +20 -0
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
|
|
|
@@ -98,6 +102,8 @@ dinou main features are:
|
|
|
98
102
|
|
|
99
103
|
- [Styles (Tailwind.css, .module.css, and .css)](#styles-tailwindcss-modulecss-and-css)
|
|
100
104
|
|
|
105
|
+
- [Images (`.png`, `.jpeg`, `.jpg`, `.gif`, `.svg`, and `.webp`)](#images-png-jpeg-jpg-gif-svg-and-webp)
|
|
106
|
+
|
|
101
107
|
- [How to run a dinou app](#how-to-run-a-dinou-app)
|
|
102
108
|
|
|
103
109
|
- [Eject dinou](#eject-dinou)
|
|
@@ -985,7 +991,7 @@ dinou is ready to use Tailwind.css, `.module.css`, and `.css` styles. All styles
|
|
|
985
991
|
|
|
986
992
|
- The above will produce the text `hi world!` in red, underlined, and with a purple background color.
|
|
987
993
|
|
|
988
|
-
- **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.
|
|
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.
|
|
989
995
|
|
|
990
996
|
- Example with server components:
|
|
991
997
|
|
|
@@ -1067,6 +1073,39 @@ dinou is ready to use Tailwind.css, `.module.css`, and `.css` styles. All styles
|
|
|
1067
1073
|
import "./page.module.css";
|
|
1068
1074
|
```
|
|
1069
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
|
+
|
|
1070
1109
|
## How to run a dinou app
|
|
1071
1110
|
|
|
1072
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.
|
|
@@ -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,3 +1,4 @@
|
|
|
1
|
+
const addHook = require("./asset-require-hook.js");
|
|
1
2
|
const { register } = require("esbuild-register/dist/node");
|
|
2
3
|
register({
|
|
3
4
|
target: "esnext",
|
|
@@ -8,6 +9,15 @@ const createScopedName = require("./createScopedName");
|
|
|
8
9
|
require("css-modules-require-hook")({
|
|
9
10
|
generateScopedName: createScopedName,
|
|
10
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
|
+
|
|
11
21
|
const { renderToPipeableStream } = require("react-dom/server");
|
|
12
22
|
const { getJSX, getSSGJSX } = require("./get-jsx");
|
|
13
23
|
const { renderJSXToClientJSX } = require("./render-jsx-to-client-jsx");
|
|
@@ -27,6 +37,7 @@ async function renderToStream() {
|
|
|
27
37
|
onError(error) {
|
|
28
38
|
console.error("Render error:", error);
|
|
29
39
|
process.stderr.write(JSON.stringify({ error: error.message }));
|
|
40
|
+
process.exit(1);
|
|
30
41
|
},
|
|
31
42
|
onShellReady() {
|
|
32
43
|
stream.pipe(process.stdout);
|
|
@@ -39,9 +50,16 @@ async function renderToStream() {
|
|
|
39
50
|
}
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
renderToStream();
|
|
44
|
-
} catch (error) {
|
|
53
|
+
process.on("uncaughtException", (error) => {
|
|
45
54
|
process.stderr.write(JSON.stringify({ error: error.message }));
|
|
46
55
|
process.exit(1);
|
|
47
|
-
}
|
|
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
|
@@ -11,19 +11,25 @@ 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
|
-
|
|
14
|
+
const addHook = require("./asset-require-hook.js");
|
|
15
15
|
webpackRegister();
|
|
16
16
|
register({
|
|
17
17
|
target: "esnext",
|
|
18
18
|
format: "cjs",
|
|
19
19
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
20
20
|
});
|
|
21
|
-
|
|
22
21
|
const createScopedName = require("./createScopedName");
|
|
23
|
-
|
|
24
22
|
require("css-modules-require-hook")({
|
|
25
23
|
generateScopedName: createScopedName,
|
|
26
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
|
+
});
|
|
27
33
|
|
|
28
34
|
const app = express();
|
|
29
35
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
|
@@ -72,22 +78,27 @@ function renderAppToHtml(reqPath, paramsString) {
|
|
|
72
78
|
|
|
73
79
|
let errorOutput = "";
|
|
74
80
|
child.stderr.on("data", (data) => {
|
|
75
|
-
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);
|
|
76
90
|
});
|
|
77
91
|
|
|
78
92
|
child.on("close", (code) => {
|
|
79
93
|
if (code !== 0) {
|
|
80
94
|
try {
|
|
81
95
|
const errorResult = JSON.parse(errorOutput);
|
|
82
|
-
reject(new Error(errorResult.error));
|
|
96
|
+
reject(new Error(errorResult.error || errorOutput));
|
|
83
97
|
} catch {
|
|
84
98
|
reject(new Error(`Child process failed: ${errorOutput}`));
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
101
|
});
|
|
88
|
-
|
|
89
|
-
// Resolve the stream from the child process
|
|
90
|
-
resolve(child.stdout);
|
|
91
102
|
});
|
|
92
103
|
}
|
|
93
104
|
|
package/dinou/ssg.js
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
const { register } = require("esbuild-register/dist/node");
|
|
2
2
|
const { buildStaticPages } = require("./build-static-pages");
|
|
3
|
-
|
|
3
|
+
const addHook = require("./asset-require-hook.js");
|
|
4
4
|
register({
|
|
5
5
|
target: "esnext",
|
|
6
6
|
format: "cjs",
|
|
7
7
|
extensions: [".js", ".jsx", ".ts", ".tsx"],
|
|
8
8
|
});
|
|
9
|
-
|
|
10
9
|
const createScopedName = require("./createScopedName");
|
|
11
|
-
|
|
12
10
|
require("css-modules-require-hook")({
|
|
13
11
|
generateScopedName: createScopedName,
|
|
14
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
|
+
});
|
|
15
21
|
|
|
16
22
|
(async () => await buildStaticPages())();
|
package/eject.js
CHANGED
|
@@ -23,10 +23,11 @@ if (fs.existsSync(path.join(modulePath, "postcss.config.js"))) {
|
|
|
23
23
|
);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
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
|
+
// );
|
|
30
31
|
|
|
31
32
|
const pkg = require(path.join(projectRoot, "package.json"));
|
|
32
33
|
pkg.scripts.dev =
|
package/package.json
CHANGED
|
@@ -1,54 +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
|
-
"@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
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"postcss
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"webpack
|
|
47
|
-
"webpack-
|
|
48
|
-
"webpack-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"react
|
|
53
|
-
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "dinou",
|
|
3
|
+
"version": "1.3.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
|
+
"@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
|
@@ -75,6 +75,26 @@ module.exports = {
|
|
|
75
75
|
},
|
|
76
76
|
],
|
|
77
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
|
+
},
|
|
78
98
|
],
|
|
79
99
|
},
|
|
80
100
|
plugins: [
|