@rspack/core 0.0.1 → 0.0.4

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +1 -0
  3. package/bin.js +1 -0
  4. package/example/basic.ts +71 -0
  5. package/example/react-example/index.html +12 -0
  6. package/example/react-example/package.json +17 -0
  7. package/example/react-example/rspack.config.json +13 -0
  8. package/example/react-example/src/app.jsx +44 -0
  9. package/example/react-example/src/base.css +9 -0
  10. package/example/react-example/src/button.jsx +3 -0
  11. package/example/react-example/src/dark.svg +1 -0
  12. package/example/react-example/src/data.json +5 -0
  13. package/example/react-example/src/file.jpg +0 -0
  14. package/example/react-example/src/file.png +0 -0
  15. package/example/react-example/src/file.svg +1 -0
  16. package/example/react-example/src/foo.css +3 -0
  17. package/example/react-example/src/index.html +32 -0
  18. package/example/react-example/src/index.js +1 -0
  19. package/example/react-example/src/light.svg +48 -0
  20. package/example/react-example/src/logo.svg +18 -0
  21. package/example/react-with-sass.ts +28 -0
  22. package/package.json +45 -13
  23. package/src/bin/index.ts +36 -0
  24. package/src/build.ts +8 -0
  25. package/src/config/builtins.ts +5 -0
  26. package/src/config/context.ts +3 -0
  27. package/src/config/define.ts +3 -0
  28. package/src/config/dev.ts +32 -0
  29. package/src/config/entry.ts +3 -0
  30. package/src/config/external.ts +3 -0
  31. package/src/config/index.ts +80 -0
  32. package/src/config/mode.ts +2 -0
  33. package/src/config/module.ts +240 -0
  34. package/src/config/output.ts +29 -0
  35. package/src/config/plugin.ts +6 -0
  36. package/src/config/resolve.ts +6 -0
  37. package/src/config/target.ts +28 -0
  38. package/src/index.ts +140 -0
  39. package/src/server/index.ts +0 -0
  40. package/tests/config.test.ts +40 -0
  41. package/tsconfig.json +14 -0
  42. package/index.js +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,31 @@
1
+ # @rspack/core
2
+
3
+ ## 0.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - d466288: add process_assets hook
8
+ - Updated dependencies [d466288]
9
+ - @rspack/binding@0.0.5
10
+ - @rspack/dev-server@0.0.4
11
+ - @rspack/plugin-postcss@0.0.4
12
+
13
+ ## 0.0.3
14
+
15
+ ### Patch Changes
16
+
17
+ - 536f6f70: fix broken lib
18
+ - Updated dependencies [536f6f70]
19
+ - @rspack/binding@0.0.4
20
+ - @rspack/dev-server@0.0.3
21
+ - @rspack/plugin-postcss@0.0.3
22
+
23
+ ## 0.0.2
24
+
25
+ ### Patch Changes
26
+
27
+ - bd57e818: first release
28
+ - Updated dependencies [bd57e818]
29
+ - @rspack/binding@0.0.2
30
+ - rspack-dev-server@0.0.2
31
+ - rspack-plugin-postcss@0.0.2
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # rspack
package/bin.js ADDED
@@ -0,0 +1 @@
1
+ require("./dist/bin/index");
@@ -0,0 +1,71 @@
1
+ import path from "path";
2
+ import postcssLoader from "@rspack/plugin-postcss";
3
+ import { Rspack } from "../src";
4
+
5
+ const rspack = new Rspack({
6
+ entry: {
7
+ main: path.resolve(__dirname, "../../../examples/postcss/index.js")
8
+ },
9
+ context: path.resolve(__dirname, "../../../examples/postcss"),
10
+ plugins: [
11
+ {
12
+ name: "test",
13
+ apply(compiler) {
14
+ compiler.hooks.done.tap("done1", () => {
15
+ console.log("done1");
16
+ });
17
+ compiler.hooks.done.tap("done2", () => {
18
+ console.log("done2");
19
+ });
20
+ compiler.hooks.compilation.tap("compilation", compilation => {
21
+ compilation.hooks.processAssets.tapPromise(
22
+ "processAssets1",
23
+ async assets => {
24
+ for (const value of Object.values(assets)) {
25
+ console.log("value:", value.buffer(), value.source());
26
+ }
27
+ compilation.emitAsset("test.js", {
28
+ source: "hello world"
29
+ });
30
+ compilation.updateAsset("main.js", {
31
+ source: "hello main"
32
+ });
33
+ }
34
+ );
35
+ });
36
+ }
37
+ }
38
+ ],
39
+ module: {
40
+ rules: [
41
+ {
42
+ test: ".module.css$",
43
+ uses: [
44
+ {
45
+ loader: postcssLoader,
46
+ options: {
47
+ modules: true
48
+ }
49
+ }
50
+ // {
51
+ // loader: function testLoader(loaderContext) {
52
+ // // console.log(loaderContext);
53
+ // return {
54
+ // content: loaderContext.source.getBufFer(),
55
+ // meta: Buffer.from("something")
56
+ // };
57
+ // }
58
+ // }
59
+ ]
60
+ }
61
+ ]
62
+ }
63
+ });
64
+
65
+ async function main() {
66
+ const stats = await rspack.build();
67
+ console.log(stats);
68
+ // assert(stats.assets.length > 0)
69
+ }
70
+
71
+ main();
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Document</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ </body>
12
+ </html>
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "react-example",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "dev": "rspack dev rspack.config.json"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "@rspack/core": "workspace:*",
14
+ "react": "17.0.0",
15
+ "react-dom": "17.0.0"
16
+ }
17
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "mode": "development",
3
+ "entry": {
4
+ "main": "./src/index.js"
5
+ },
6
+ "dev": {
7
+ "port": 8081,
8
+ "static": {
9
+ "directory": "dist"
10
+ }
11
+ },
12
+ "plugins": ["html"]
13
+ }
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import './base.css';
4
+ import LogoJPG from './file.jpg';
5
+ import LogoPNG from './file.png';
6
+ import LogoSVG from './file.svg';
7
+ import Json from './data.json';
8
+ // import Dark from './dark.svg';
9
+ // import Light from './light.svg'
10
+ // import LogoUrl from './logo.svg'
11
+ // import Logo from './logo.svg'
12
+ // const Button = React.lazy(() => import('../src/button'))
13
+
14
+ // console.log('LogoUrl', LogoUrl)
15
+ // console.log('Logo', Logo)
16
+
17
+ const App = () => {
18
+ return (
19
+ <React.Suspense fallback={<div>loading...</div>}>
20
+ <div>hello world</div>
21
+ {/* <Button></Button> */}
22
+
23
+ <img
24
+ style={{ width: '40px', height: '40px' }}
25
+ src={LogoJPG}
26
+ alt="logo jpg"
27
+ />
28
+ <img
29
+ style={{ width: '40px', height: '40px' }}
30
+ src={LogoPNG}
31
+ alt="logo png"
32
+ />
33
+ <img
34
+ style={{ width: '40px', height: '40px' }}
35
+ src={LogoSVG}
36
+ alt="logo svg"
37
+ />
38
+ {/* <Logo width={'40px'} height={'40px'} />
39
+ <Light width={'40px'} height={'40px'} />
40
+ <Dark width={'40px'} height={'40px'} /> */}
41
+ </React.Suspense>
42
+ );
43
+ };
44
+ ReactDOM.render(<App />, document.getElementById('root'));
@@ -0,0 +1,9 @@
1
+ @import './foo.css';
2
+
3
+ body {
4
+ background: gray;
5
+ background-image: url('./logo.svg');
6
+ }
7
+ .class {
8
+ box-shadow: 10px 5px 5px red;
9
+ }
@@ -0,0 +1,3 @@
1
+ import React from 'react'
2
+ const button = () => <div>cute button</div>
3
+ export default button
@@ -0,0 +1 @@
1
+ <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1599669065723" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18411" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M390 250c0-52.6 10.6-102.6 29.8-148.2C237.4 146 102 310.2 102 506c0 229.6 186.4 416 416 416 195.8 0 360-135.4 404.2-317.8-45.6 19.2-95.8 29.8-148.2 29.8-212 0-384-172-384-384z" p-id="18412"></path></svg>
@@ -0,0 +1,5 @@
1
+ {
2
+ "escaped": "\\u2028",
3
+ "LS": "
",
4
+ "PS": "
"
5
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600"><title>icon-square-small</title><path fill="#FFF" d="M300 .1L565 150v299.9L300 599.8 35 449.9V150z"/><path fill="#8ED6FB" d="M517.7 439.5L308.8 557.8v-92L439 394.1l78.7 45.4zm14.3-12.9V179.4l-76.4 44.1v159l76.4 44.1zM81.5 439.5l208.9 118.2v-92l-130.2-71.6-78.7 45.4zm-14.3-12.9V179.4l76.4 44.1v159l-76.4 44.1zm8.9-263.2L290.4 42.2v89l-137.3 75.5-1.1.6-75.9-43.9zm446.9 0L308.8 42.2v89L446 206.8l1.1.6 75.9-44z"/><path fill="#1C78C0" d="M290.4 444.8L162 374.1V234.2l128.4 74.1v136.5zm18.4 0l128.4-70.6v-140l-128.4 74.1v136.5zM299.6 303zm-129-85l129-70.9L428.5 218l-128.9 74.4-129-74.4z"/></svg>
@@ -0,0 +1,3 @@
1
+ body {
2
+ color: rebeccapurple;
3
+ }
@@ -0,0 +1,32 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <title>React App</title>
7
+ <script>
8
+ process = {
9
+ env: 'production'
10
+ }
11
+ </script>
12
+ <script src="./runtime.js"></script>
13
+ <link rel="stylesheet" href="./main.css">
14
+ </head>
15
+
16
+ <body>
17
+ <noscript>You need to enable JavaScript to run this app.</noscript>
18
+ <div id="root"></div>
19
+ <!--
20
+ This HTML file is a template.
21
+ If you open it directly in the browser, you will see an empty page.
22
+
23
+ You can add webfonts, meta tags, or analytics to this file.
24
+ The build step will place the bundled scripts into the <body> tag.
25
+
26
+ To begin the development, run `npm start` or `yarn start`.
27
+ To create a production bundle, use `npm run build` or `yarn build`.
28
+ -->
29
+ </body>
30
+ <script src="./main.js"></script>
31
+
32
+ </html>
@@ -0,0 +1 @@
1
+ import "./app.jsx";
@@ -0,0 +1,48 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
4
+ y="0px" viewBox="0 0 22 22" style="enable-background:new 0 0 22 22;" xml:space="preserve">
5
+ <style type="text/css">
6
+ .st1 {
7
+ fill: none;
8
+ }
9
+
10
+ body {
11
+ background: deepskyblue;
12
+ }
13
+ </style>
14
+ <title>编组 5备份</title>
15
+ <desc>Created with Sketch.</desc>
16
+ <g id="组件页-Web端-_xD83E__xDD1F_">
17
+ <g id="暗黑模式" transform="translate(2.500000, 2.500000)">
18
+ <g id="编组-12">
19
+ <g id="编组-8">
20
+ <g id="编组-7" transform="translate(7.285714, 0.000000)">
21
+ </g>
22
+
23
+ <g id="编组-7备份"
24
+ transform="translate(8.500000, 8.500000) rotate(-270.000000) translate(-8.500000, -8.500000) translate(7.285714, 0.000000)">
25
+ </g>
26
+
27
+ <g id="编组-7备份-2"
28
+ transform="translate(8.500000, 8.500000) rotate(-225.000000) translate(-8.500000, -8.500000) translate(7.285714, 0.000000)">
29
+ </g>
30
+
31
+ <g id="编组-7备份-3"
32
+ transform="translate(8.500000, 8.500000) rotate(-315.000000) translate(-8.500000, -8.500000) translate(7.285714, 0.000000)">
33
+ </g>
34
+ </g>
35
+ </g>
36
+ <path id="椭圆形" class="st0" d="M8.5,11.5c1.7,0,3-1.4,3-3s-1.4-3-3-3s-3,1.4-3,3S6.8,11.5,8.5,11.5z" />
37
+ <rect id="矩形" x="7.3" class="st0" width="2.4" height="2.4" />
38
+ <rect id="矩形备份-2" x="7.3" y="14.6" class="st0" width="2.4" height="2.4" />
39
+ <polygon id="矩形_1_" class="st0" points="17,7.3 17,9.7 14.6,9.7 14.6,7.3 " />
40
+ <polygon id="矩形备份-2_1_" class="st0" points="2.4,7.3 2.4,9.7 0,9.7 0,7.3 " />
41
+ <polygon id="矩形_2_" class="st0" points="15.4,13.7 13.7,15.4 11.9,13.7 13.7,11.9 " />
42
+ <polygon id="矩形备份-2_2_" class="st0" points="5.1,3.3 3.3,5.1 1.6,3.3 3.3,1.6 " />
43
+ <polygon id="矩形_3_" class="st0" points="13.7,1.6 15.4,3.3 13.7,5.1 11.9,3.3 " />
44
+ <polygon id="矩形备份-2_3_" class="st0" points="3.3,11.9 5.1,13.7 3.3,15.4 1.6,13.7 " />
45
+ </g>
46
+ </g>
47
+ <rect x="0" class="st1" width="22" height="22" />
48
+ </svg>
@@ -0,0 +1,18 @@
1
+ <svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0)">
3
+ <path fill-rule="evenodd" clip-rule="evenodd"
4
+ d="M5.37754 16.9795L12.7498 9.43027C14.7163 7.41663 17.9428 7.37837 19.9564 9.34482C19.9852 9.37297 20.0137 9.40145 20.0418 9.43027L20.1221 9.51243C22.1049 11.5429 22.1049 14.7847 20.1221 16.8152L12.7498 24.3644C10.7834 26.378 7.55686 26.4163 5.54322 24.4498C5.5144 24.4217 5.48592 24.3932 5.45777 24.3644L5.37754 24.2822C3.39468 22.2518 3.39468 19.0099 5.37754 16.9795Z"
5
+ fill="#12D2AC" />
6
+ <path fill-rule="evenodd" clip-rule="evenodd"
7
+ d="M20.0479 9.43034L27.3399 16.8974C29.3674 18.9735 29.3674 22.2883 27.3399 24.3644C25.3735 26.3781 22.147 26.4163 20.1333 24.4499C20.1045 24.4217 20.076 24.3933 20.0479 24.3644L12.7558 16.8974C10.7284 14.8213 10.7284 11.5065 12.7558 9.43034C14.7223 7.4167 17.9488 7.37844 19.9624 9.34489C19.9912 9.37304 20.0197 9.40152 20.0479 9.43034Z"
8
+ fill="#307AF2" />
9
+ <path fill-rule="evenodd" clip-rule="evenodd"
10
+ d="M20.1321 9.52163L23.6851 13.1599L16.3931 20.627L9.10103 13.1599L12.6541 9.52163C14.6707 7.45664 17.9794 7.4174 20.0444 9.434C20.074 9.46286 20.1032 9.49207 20.1321 9.52163Z"
11
+ fill="#0057FE" />
12
+ </g>
13
+ <defs>
14
+ <clipPath id="clip0">
15
+ <rect width="26" height="19" fill="white" transform="translate(3.5 7)" />
16
+ </clipPath>
17
+ </defs>
18
+ </svg>
@@ -0,0 +1,28 @@
1
+ import path from "path";
2
+ import { Rspack } from "../src";
3
+
4
+ const context = path.resolve(__dirname, "../../../examples/react-with-sass");
5
+
6
+ const rspack = new Rspack({
7
+ entry: {
8
+ main: path.resolve(context, "./src/index.jsx")
9
+ },
10
+ context,
11
+ plugins: ["html"],
12
+ module: {
13
+ rules: [
14
+ {
15
+ test: "\\.s[ac]ss$",
16
+ uses: [{ builtinLoader: "sass-loader" }],
17
+ type: "css"
18
+ }
19
+ ]
20
+ }
21
+ });
22
+
23
+ async function main() {
24
+ const stats = await rspack.build();
25
+ console.log(stats);
26
+ }
27
+
28
+ main();
package/package.json CHANGED
@@ -1,18 +1,50 @@
1
1
  {
2
2
  "name": "@rspack/core",
3
- "version": "0.0.1",
4
- "description": "",
5
- "main": "index.js",
6
- "publishConfig": {
7
- "access": "public"
3
+ "version": "0.0.4",
4
+ "bin": {
5
+ "rspack": "./bin.js"
8
6
  },
9
- "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "main": "./lib/index.js",
8
+ "types": "./lib/index.d.ts",
9
+ "devDependencies": {
10
+ "@types/node": "^18.6.3",
11
+ "tsm": "^2.2.2",
12
+ "ts-node": "10.9.1",
13
+ "typescript": "4.7.3",
14
+ "@types/ws": "8.5.3",
15
+ "@types/connect": "3.4.35",
16
+ "uvu": "0.5.6",
17
+ "@rspack/core": "0.0.4",
18
+ "@types/webpack-sources": "3.2.0"
11
19
  },
12
- "keywords": [],
13
- "author": "",
14
- "license": "ISC",
15
20
  "dependencies": {
16
- "lodash-es": "^4.17.21"
17
- }
18
- }
21
+ "@rspack/binding": "0.0.5",
22
+ "commander": "9.4.0",
23
+ "ws": "8.8.1",
24
+ "connect": "3.7.0",
25
+ "chokidar": "3.5.3",
26
+ "open": "8.4.0",
27
+ "clipanion": "3.2.0-rc.11",
28
+ "@rspack/dev-server": "^0.0.4",
29
+ "sirv": "2.0.2",
30
+ "@rspack/plugin-postcss": "^0.0.4",
31
+ "tapable": "2.2.1",
32
+ "webpack-sources": "3.2.3"
33
+ },
34
+ "optionalDependencies": {
35
+ "@tmp-sass-embedded/darwin-arm64": "1.54.4",
36
+ "@tmp-sass-embedded/darwin-x64": "1.54.4",
37
+ "@tmp-sass-embedded/linux-arm64": "1.54.4",
38
+ "@tmp-sass-embedded/linux-ia32": "1.54.4",
39
+ "@tmp-sass-embedded/linux-x64": "1.54.4",
40
+ "@tmp-sass-embedded/win32-ia32": "1.54.4",
41
+ "@tmp-sass-embedded/win32-x64": "1.54.4"
42
+ },
43
+ "scripts": {
44
+ "build": "rm -rf lib/ && tsc",
45
+ "dev": "tsc -w",
46
+ "example": "node -r ts-node/register ./example/basic.ts",
47
+ "test": "uvu -r tsm tests"
48
+ },
49
+ "readme": "# rspack\n"
50
+ }
@@ -0,0 +1,36 @@
1
+ import { Command } from "commander";
2
+ import { createServer } from "@rspack/dev-server";
3
+ import { Rspack } from "..";
4
+ import fs from "fs";
5
+ import { build } from "../build";
6
+
7
+ const program = new Command();
8
+
9
+ program
10
+ .option("--env", "env")
11
+ .command("build", {
12
+ isDefault: true
13
+ })
14
+ .description("Rspack build cli")
15
+
16
+ .argument("<config-file>", "rspack config file path")
17
+ .action(async configPath => {
18
+ const config = require(configPath);
19
+ const stats = await build(config);
20
+ console.log(stats);
21
+ });
22
+
23
+ program
24
+ .command("dev")
25
+ .description("Rspack build cli")
26
+ .argument("<config-file>", "rspack config file path")
27
+ .action(async configPath => {
28
+ const config = require(configPath);
29
+ const rspack = new Rspack(config);
30
+ const { options: { dev: { port = 8080 } = {} } = {} } = rspack;
31
+ await rspack.build();
32
+ const server = await createServer(rspack.options);
33
+ server.listen(port, () => console.log(`Server listening on port: ${port}`));
34
+ });
35
+
36
+ program.parse();
package/src/build.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { Rspack } from ".";
2
+ export async function build(config: any) {
3
+ const rspack = new Rspack(config);
4
+ const stats = await rspack.build();
5
+ if (stats.errors.length > 0) {
6
+ throw new Error(stats.errors[0].message);
7
+ }
8
+ }
@@ -0,0 +1,5 @@
1
+ import type { RawBuiltins } from "@rspack/binding";
2
+
3
+ export type Builtins = RawBuiltins;
4
+
5
+ export type ResolvedBuiltins = RawBuiltins | any[];
@@ -0,0 +1,3 @@
1
+ export type Context = string;
2
+
3
+ export type ResolvedContext = string;
@@ -0,0 +1,3 @@
1
+ export type Define = Record<string, string>;
2
+
3
+ export type ResolvedDefine = Record<string, string>;
@@ -0,0 +1,32 @@
1
+ import path from "node:path";
2
+
3
+ export interface Dev {
4
+ port?: number;
5
+ static?: {
6
+ directory?: string;
7
+ };
8
+ }
9
+
10
+ export interface ResolvedDev {
11
+ port: number;
12
+ static: {
13
+ directory: string;
14
+ };
15
+ }
16
+
17
+ interface ResolveDevConfigContext {
18
+ context: string;
19
+ }
20
+
21
+ export function resolveDevOptions(
22
+ devConfig: Dev = {},
23
+ context: ResolveDevConfigContext
24
+ ): ResolvedDev {
25
+ return {
26
+ port: devConfig.port ?? 8080,
27
+ static: {
28
+ directory:
29
+ devConfig.static?.directory ?? path.resolve(context.context, "dist")
30
+ }
31
+ };
32
+ }
@@ -0,0 +1,3 @@
1
+ export type Entry = Record<string, string>;
2
+
3
+ export type ResolvedEntry = Record<string, string>;
@@ -0,0 +1,3 @@
1
+ export type External = Record<string, string>;
2
+
3
+ export type ResolvedExternal = Record<string, string>;
@@ -0,0 +1,80 @@
1
+ import type { Context, ResolvedContext } from "./context";
2
+ import type { Define, ResolvedDefine } from "./define";
3
+ import type { Dev, ResolvedDev } from "./dev";
4
+ import type { Entry, ResolvedEntry } from "./entry";
5
+ import type { External, ResolvedExternal } from "./external";
6
+ import type { Mode, ResolvedMode } from "./mode";
7
+ import type { Module, ResolvedModule } from "./module";
8
+ import type { Plugin } from "./plugin";
9
+ import type { ResolvedTarget, Target } from "./target";
10
+ import type { Output, ResolvedOutput } from "./output";
11
+ import { resolveTargetOptions } from "./target";
12
+ import { resolveOutputOptions } from "./output";
13
+ import { resolveDevOptions } from "./dev";
14
+ import { resolveModuleOptions } from "./module";
15
+ import { Builtins, ResolvedBuiltins } from "./builtins";
16
+ import { Resolve, ResolvedResolve } from "./resolve";
17
+
18
+ export type Asset = {
19
+ source: string;
20
+ };
21
+ export type Assets = Record<string, Asset>;
22
+
23
+ export interface RspackOptions {
24
+ entry?: Entry;
25
+ context?: Context;
26
+ plugins?: Plugin[];
27
+ dev?: Dev;
28
+ module?: Module;
29
+ define?: Define;
30
+ target?: Target;
31
+ mode?: Mode;
32
+ external?: External;
33
+ output?: Output;
34
+ builtins: Builtins;
35
+ resolve: Resolve;
36
+ }
37
+
38
+ export interface ResolvedRspackOptions {
39
+ entry: ResolvedEntry;
40
+ context: ResolvedContext;
41
+ plugins: Plugin[];
42
+ dev: ResolvedDev;
43
+ module: ResolvedModule;
44
+ define: ResolvedDefine;
45
+ target: ResolvedTarget;
46
+ mode: ResolvedMode;
47
+ external: ResolvedExternal;
48
+ output: ResolvedOutput;
49
+ builtins: ResolvedBuiltins;
50
+ resolve: ResolvedResolve;
51
+ }
52
+
53
+ export function resolveOptions(config: RspackOptions): ResolvedRspackOptions {
54
+ const context = config.context ?? process.cwd();
55
+ const mode = config.mode ?? "development";
56
+ const dev = resolveDevOptions(config.dev, { context });
57
+ const entry = config.entry ?? {};
58
+ const output = resolveOutputOptions(config.output);
59
+ const define = config.define ?? {};
60
+ const target = resolveTargetOptions(config.target);
61
+ const external = config.external ?? {};
62
+ const plugins = config.plugins ?? [];
63
+ const builtins = config.builtins ?? [];
64
+ const resolve = config.resolve ?? {};
65
+ const module = resolveModuleOptions(config.module);
66
+ return {
67
+ context,
68
+ mode,
69
+ dev,
70
+ entry,
71
+ output,
72
+ define,
73
+ target,
74
+ external,
75
+ plugins,
76
+ builtins,
77
+ module,
78
+ resolve
79
+ };
80
+ }
@@ -0,0 +1,2 @@
1
+ export type Mode = string;
2
+ export type ResolvedMode = string;
@@ -0,0 +1,240 @@
1
+ import type { RawModuleRuleUse, RawModuleRule } from "@rspack/binding";
2
+ import assert from "node:assert";
3
+
4
+ export interface ModuleRule {
5
+ test?: RawModuleRule["test"];
6
+ resource?: RawModuleRule["resource"];
7
+ resourceQuery?: RawModuleRule["resourceQuery"];
8
+ uses?: ModuleRuleUse[];
9
+ type?: RawModuleRule["type"];
10
+ }
11
+
12
+ export interface Module {
13
+ rules?: ModuleRule[];
14
+ parser?: {
15
+ dataUrlCondition?: {
16
+ maxSize?: number;
17
+ };
18
+ };
19
+ }
20
+
21
+ interface ResolvedModuleRule {
22
+ test?: RawModuleRule["test"];
23
+ resource?: RawModuleRule["resource"];
24
+ resourceQuery?: RawModuleRule["resourceQuery"];
25
+ uses?: RawModuleRuleUse[];
26
+ type?: RawModuleRule["type"];
27
+ }
28
+
29
+ export interface ResolvedModule {
30
+ rules: ResolvedModuleRule[];
31
+ parser?: {
32
+ dataUrlCondition: {
33
+ maxSize: number;
34
+ };
35
+ };
36
+ }
37
+
38
+ interface LoaderContextInternal {
39
+ // TODO: It's not a good way to do this, we should split the `source` into a separate type and avoid using `serde_json`, but it's a temporary solution.
40
+ source: number[];
41
+ resource: String;
42
+ resourcePath: String;
43
+ resourceQuery: String | null;
44
+ resourceFragment: String | null;
45
+ }
46
+
47
+ interface LoaderResult {
48
+ content: Buffer | string;
49
+ meta: Buffer | string;
50
+ }
51
+
52
+ interface LoaderThreadsafeResult {
53
+ id: number;
54
+ p: LoaderResultInternal | null | undefined;
55
+ }
56
+
57
+ interface LoaderResultInternal {
58
+ content: number[];
59
+ meta: number[];
60
+ }
61
+
62
+ interface LoaderContext
63
+ extends Pick<
64
+ LoaderContextInternal,
65
+ "resource" | "resourcePath" | "resourceQuery" | "resourceFragment"
66
+ > {
67
+ source: {
68
+ getCode(): string;
69
+ getBuffer(): Buffer;
70
+ };
71
+ }
72
+
73
+ const toBuffer = (bufLike: string | Buffer): Buffer => {
74
+ if (Buffer.isBuffer(bufLike)) {
75
+ return bufLike;
76
+ } else if (typeof bufLike === "string") {
77
+ return Buffer.from(bufLike);
78
+ }
79
+
80
+ throw new Error("Buffer or string expected");
81
+ };
82
+
83
+ interface LoaderThreadsafeContext {
84
+ id: number;
85
+ p: LoaderContextInternal;
86
+ }
87
+
88
+ function composeJsUse(uses: ModuleRuleUse[]): RawModuleRuleUse | null {
89
+ if (!uses.length) {
90
+ return null;
91
+ }
92
+
93
+ async function loader(err: any, data: Buffer): Promise<Buffer> {
94
+ if (err) {
95
+ throw err;
96
+ }
97
+
98
+ const loaderThreadsafeContext: LoaderThreadsafeContext = JSON.parse(
99
+ data.toString("utf-8")
100
+ );
101
+
102
+ const { p: payload, id } = loaderThreadsafeContext;
103
+
104
+ const loaderContextInternal: LoaderContextInternal = {
105
+ source: payload.source,
106
+ resourcePath: payload.resourcePath,
107
+ resourceQuery: payload.resourceQuery,
108
+ resource: payload.resource,
109
+ resourceFragment: payload.resourceFragment
110
+ };
111
+
112
+ let sourceBuffer = Buffer.from(loaderContextInternal.source);
113
+ let meta = Buffer.from("");
114
+ // Loader is executed from right to left
115
+ for (const use of uses) {
116
+ assert("loader" in use);
117
+ const loaderContext = {
118
+ ...loaderContextInternal,
119
+ source: {
120
+ getCode(): string {
121
+ return sourceBuffer.toString("utf-8");
122
+ },
123
+ getBuffer(): Buffer {
124
+ return sourceBuffer;
125
+ }
126
+ },
127
+ getOptions() {
128
+ return use.options;
129
+ }
130
+ };
131
+
132
+ let loaderResult: LoaderResult;
133
+ if (
134
+ (loaderResult = await Promise.resolve().then(() =>
135
+ use.loader.apply(loaderContext, [loaderContext])
136
+ ))
137
+ ) {
138
+ const content = loaderResult.content;
139
+ meta = meta.length > 0 ? meta : toBuffer(loaderResult.meta);
140
+ sourceBuffer = toBuffer(content);
141
+ }
142
+ }
143
+
144
+ const loaderResultPayload: LoaderResultInternal = {
145
+ content: [...sourceBuffer],
146
+ meta: [...meta]
147
+ };
148
+
149
+ const loaderThreadsafeResult: LoaderThreadsafeResult = {
150
+ id: id,
151
+ p: loaderResultPayload
152
+ };
153
+ return Buffer.from(JSON.stringify(loaderThreadsafeResult), "utf-8");
154
+ }
155
+ loader.displayName = `NodeLoaderAdapter(${uses
156
+ .map(item => {
157
+ assert("loader" in item);
158
+ return item.loader.displayName || item.loader.name || "unknown-loader";
159
+ })
160
+ .join(" -> ")})`;
161
+ return {
162
+ loader
163
+ };
164
+ }
165
+
166
+ interface JsLoader {
167
+ (this: LoaderContext, loaderContext: LoaderContext):
168
+ | Promise<LoaderResult | void>
169
+ | LoaderResult
170
+ | void;
171
+ displayName?: string;
172
+ }
173
+
174
+ type BuiltinLoader = string;
175
+
176
+ type ModuleRuleUse =
177
+ | {
178
+ builtinLoader: BuiltinLoader;
179
+ options?: unknown;
180
+ }
181
+ | {
182
+ loader: JsLoader;
183
+ options?: unknown;
184
+ };
185
+
186
+ export function createRawModuleRuleUses(
187
+ uses: ModuleRuleUse[]
188
+ ): RawModuleRuleUse[] {
189
+ return createRawModuleRuleUsesImpl([...uses].reverse());
190
+ }
191
+
192
+ function createRawModuleRuleUsesImpl(
193
+ uses: ModuleRuleUse[]
194
+ ): RawModuleRuleUse[] {
195
+ if (!uses.length) {
196
+ return [];
197
+ }
198
+
199
+ const index = uses.findIndex(use => "builtinLoader" in use);
200
+ if (index < 0) {
201
+ return [composeJsUse(uses)];
202
+ }
203
+
204
+ const before = uses.slice(0, index);
205
+ const after = uses.slice(index + 1);
206
+ return [
207
+ composeJsUse(before),
208
+ createNativeUse(uses[index]),
209
+ ...createRawModuleRuleUsesImpl(after)
210
+ ].filter((item): item is RawModuleRuleUse => Boolean(item));
211
+ }
212
+
213
+ function createNativeUse(use: ModuleRuleUse): RawModuleRuleUse {
214
+ assert("builtinLoader" in use);
215
+
216
+ if (use.builtinLoader === "sass-loader") {
217
+ (use.options ??= {} as any).__exePath = require.resolve(
218
+ `@tmp-sass-embedded/${process.platform}-${
219
+ process.arch
220
+ }/dart-sass-embedded/dart-sass-embedded${
221
+ process.platform === "win32" ? ".bat" : ""
222
+ }`
223
+ );
224
+ }
225
+
226
+ return {
227
+ builtinLoader: use.builtinLoader,
228
+ options: JSON.stringify(use.options)
229
+ };
230
+ }
231
+
232
+ export function resolveModuleOptions(module: Module = {}): ResolvedModule {
233
+ const rules = (module.rules ?? []).map(rule => ({
234
+ ...rule,
235
+ uses: createRawModuleRuleUses(rule.uses || [])
236
+ }));
237
+ return {
238
+ rules
239
+ };
240
+ }
@@ -0,0 +1,29 @@
1
+ export interface Output {
2
+ path?: string;
3
+ publicPath?: string;
4
+ assetModuleFilename?: string;
5
+ filename?: string;
6
+ chunkFilename?: string;
7
+ uniqueName?: string;
8
+ }
9
+
10
+ // TODO: fix it
11
+ export interface ResolvedOutput {
12
+ path?: string;
13
+ publicPath?: string;
14
+ assetModuleFilename?: string;
15
+ filename?: string;
16
+ chunkFilename?: string;
17
+ uniqueName?: string;
18
+ }
19
+
20
+ export function resolveOutputOptions(output: Output = {}): ResolvedOutput {
21
+ return {
22
+ path: output.path,
23
+ publicPath: output.publicPath,
24
+ chunkFilename: output.chunkFilename,
25
+ filename: output.publicPath,
26
+ assetModuleFilename: output.assetModuleFilename,
27
+ uniqueName: output.uniqueName
28
+ };
29
+ }
@@ -0,0 +1,6 @@
1
+ import Rspack from "..";
2
+
3
+ export interface Plugin {
4
+ name: string;
5
+ apply(compiler: Rspack): void;
6
+ }
@@ -0,0 +1,6 @@
1
+ export type Resolve = {
2
+ preferRelative?: boolean;
3
+ };
4
+ export type ResolvedResolve = {
5
+ preferRelative?: boolean;
6
+ };
@@ -0,0 +1,28 @@
1
+ type TargetItem =
2
+ | "web"
3
+ | "webworker"
4
+ | "browserslist"
5
+ | "es3"
6
+ | "es5"
7
+ | "es2015"
8
+ | "es2016"
9
+ | "es2017"
10
+ | "es2018"
11
+ | "es2019"
12
+ | "es2020"
13
+ | "es2021"
14
+ | "es2022";
15
+
16
+ export type Target = TargetItem | TargetItem[] | false;
17
+ export type ResolvedTarget = TargetItem[];
18
+
19
+ export function resolveTargetOptions(target: Target = "web"): ResolvedTarget {
20
+ if (!target) {
21
+ return [];
22
+ }
23
+ if (!Array.isArray(target)) {
24
+ return [target];
25
+ }
26
+
27
+ return target;
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,140 @@
1
+ export * from "./build";
2
+ import * as binding from "@rspack/binding";
3
+ import type { ExternalObject, RspackInternal } from "@rspack/binding";
4
+ import * as tapable from "tapable";
5
+ import {
6
+ RspackOptions,
7
+ ResolvedRspackOptions,
8
+ Assets,
9
+ Asset,
10
+ resolveOptions
11
+ } from "./config";
12
+
13
+ import { RawSource, Source } from "webpack-sources";
14
+ interface RspackThreadsafeContext<T> {
15
+ readonly id: number;
16
+ readonly inner: T;
17
+ }
18
+ interface RspackThreadsafeResult<T> {
19
+ readonly id: number;
20
+ readonly inner: T;
21
+ }
22
+ const createDummyResult = (id: number): string => {
23
+ const result: RspackThreadsafeResult<null> = {
24
+ id,
25
+ inner: null
26
+ };
27
+ return JSON.stringify(result);
28
+ };
29
+ type EmitAssetCallback = (options: { filename: string; asset: Asset }) => void;
30
+ class RspackCompilation {
31
+ #emitAssetCallback: EmitAssetCallback;
32
+ hooks: {
33
+ processAssets: tapable.AsyncSeriesHook<Record<string, Source>>;
34
+ };
35
+ constructor() {
36
+ this.hooks = {
37
+ processAssets: new tapable.AsyncSeriesHook<Record<string, Source>>([
38
+ "assets"
39
+ ])
40
+ };
41
+ }
42
+ /**
43
+ * unsafe to call out of processAssets
44
+ * @param filename
45
+ * @param asset
46
+ */
47
+ updateAsset(filename: string, asset: Asset) {
48
+ this.emitAsset(filename, asset);
49
+ }
50
+ /**
51
+ * unsafe to call out of processAssets
52
+ * @param filename
53
+ * @param asset
54
+ */
55
+ emitAsset(filename: string, asset: Asset) {
56
+ if (!this.#emitAssetCallback) {
57
+ throw new Error("can't call emitAsset outof processAssets hook for now");
58
+ }
59
+ this.#emitAssetCallback({
60
+ filename: filename,
61
+ asset
62
+ });
63
+ }
64
+ async processAssets(err: Error, value: string, emitAsset: any) {
65
+ this.#emitAssetCallback = emitAsset;
66
+ if (err) {
67
+ throw err;
68
+ }
69
+ const context: RspackThreadsafeContext<
70
+ Record<string, { source: string | Buffer }>
71
+ > = JSON.parse(value);
72
+ let content: Record<string, { source: string | Buffer }> =
73
+ context.inner ?? {};
74
+ let assets = {};
75
+ for (const [key, value] of Object.entries(content)) {
76
+ // webpack-sources's type definition is wrong, it actually could accept Buffer type
77
+ let source = value.source;
78
+ if (Array.isArray(value.source)) {
79
+ source = Buffer.from(value.source);
80
+ }
81
+ assets[key] = new RawSource(source as string);
82
+ }
83
+ await this.hooks.processAssets.promise(assets);
84
+ return createDummyResult(context.id);
85
+ }
86
+ }
87
+ class Rspack {
88
+ #plugins: RspackOptions["plugins"];
89
+ #instance: ExternalObject<RspackInternal>;
90
+ compilation: RspackCompilation;
91
+ hooks: {
92
+ done: tapable.AsyncSeriesHook<void>;
93
+ compilation: tapable.SyncHook<RspackCompilation>;
94
+ };
95
+ options: ResolvedRspackOptions;
96
+ constructor(options: RspackOptions) {
97
+ this.options = resolveOptions(options);
98
+ // @ts-ignored
99
+ this.#instance = binding.newRspack(this.options, {
100
+ doneCallback: this.#done.bind(this),
101
+ processAssetsCallback: this.#processAssets.bind(this)
102
+ });
103
+ this.hooks = {
104
+ done: new tapable.AsyncSeriesHook<void>(),
105
+ compilation: new tapable.SyncHook<RspackCompilation>(["compilation"])
106
+ };
107
+ this.#plugins = options.plugins ?? [];
108
+ for (const plugin of this.#plugins) {
109
+ plugin.apply(this);
110
+ }
111
+ }
112
+ async #done(err: Error, value: string) {
113
+ if (err) {
114
+ throw err;
115
+ }
116
+ const context: RspackThreadsafeContext<void> = JSON.parse(value);
117
+ await this.hooks.done.promise();
118
+ return createDummyResult(context.id);
119
+ }
120
+ async #processAssets(err: Error, value: string, emitAsset: any) {
121
+ return this.compilation.processAssets(err, value, emitAsset);
122
+ }
123
+ #newCompilation() {
124
+ const compilation = new RspackCompilation();
125
+ this.compilation = compilation;
126
+ this.hooks.compilation.call(compilation);
127
+ return compilation;
128
+ }
129
+ async build() {
130
+ const compilation = this.#newCompilation();
131
+ const stats = await binding.build(this.#instance);
132
+ return stats;
133
+ }
134
+ async rebuild(changeFiles: string[]) {
135
+ const stats = await binding.rebuild(this.#instance, changeFiles);
136
+ return stats;
137
+ }
138
+ }
139
+ export { Rspack };
140
+ export default Rspack;
File without changes
@@ -0,0 +1,40 @@
1
+ import { test } from "uvu";
2
+ import * as assert from "uvu/assert";
3
+ import { Rspack } from "@rspack/core";
4
+ import path from "path";
5
+
6
+ test("default config snapshot", () => {
7
+ const resolvedOptions = new Rspack({}).options;
8
+
9
+ assert.equal(resolvedOptions.context, process.cwd());
10
+ assert.equal(
11
+ resolvedOptions.dev.static.directory,
12
+ path.resolve(process.cwd(), "./dist")
13
+ );
14
+
15
+ // TypeScript will throw `The operand of a 'delete' operator must be optional`.
16
+ // But we remove these configurations with absolute paths.
17
+ // @ts-expect-error
18
+ delete resolvedOptions.context;
19
+ // @ts-expect-error
20
+ delete resolvedOptions.dev.static.directory;
21
+
22
+ assert.snapshot(
23
+ JSON.stringify(resolvedOptions),
24
+ JSON.stringify({
25
+ mode: "development",
26
+ dev: { port: 8080, static: {} },
27
+ entry: {},
28
+ output: {},
29
+ define: {},
30
+ target: ["web"],
31
+ external: {},
32
+ plugins: [],
33
+ builtins: [],
34
+ module: { rules: [] },
35
+ resolve: {}
36
+ })
37
+ );
38
+ });
39
+
40
+ test.run();
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "CommonJS",
4
+ "target": "ES2018",
5
+ "moduleResolution": "node",
6
+ "esModuleInterop": true,
7
+ "outDir": "lib",
8
+ "declaration": true
9
+ },
10
+ "include": ["src"],
11
+ "ts-node": {
12
+ "transpileOnly": true
13
+ }
14
+ }
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = {}