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 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;
@@ -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
- try {
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
- fs.copyFileSync(
27
- path.join(modulePath, "LICENSE.md"),
28
- path.join(projectRoot, "dinou/LICENSE.md")
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.2.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
- "mini-css-extract-plugin": "^2.9.2",
41
- "postcss": "^8.5.5",
42
- "postcss-loader": "^8.1.1",
43
- "react-server-dom-webpack": "^19.1.0",
44
- "tailwindcss": "^4.1.10",
45
- "webpack": "^5.99.8",
46
- "webpack-cli": "^6.0.1",
47
- "webpack-dev-middleware": "^7.4.2",
48
- "webpack-hot-middleware": "^2.26.1"
49
- },
50
- "peerDependencies": {
51
- "react": "^19.1.0",
52
- "react-dom": "^19.1.0"
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: [