├── .github
├── renovate.json5
└── workflows
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .npmrc
├── .vscode
├── extensions.json
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── biome.jsonc
├── client-src
├── index.js
└── utils
│ └── ansiHTML.ts
├── jest.config.js
├── package.json
├── pnpm-lock.yaml
├── scripts
├── patch-node-env.cjs
└── release.mjs
├── src
├── config.ts
├── index.ts
├── patch.ts
└── server.ts
├── tests
├── ansiHTML.test.ts
├── e2e
│ ├── __snapshots__
│ │ ├── allowed-hosts.test.js.snap.webpack5
│ │ ├── api.test.js.snap.webpack5
│ │ ├── app.test.js.snap.webpack5
│ │ ├── bonjour.test.js.snap.webpack5
│ │ ├── built-in-routes.test.js.snap.webpack5
│ │ ├── client-reconnect.test.js.snap.webpack5
│ │ ├── client.test.js.snap.webpack5
│ │ ├── compress.test.js.snap.webpack5
│ │ ├── entry.test.js.snap.webpack5
│ │ ├── headers.test.js.snap.webpack5
│ │ ├── history-api-fallback.test.js.snap.webpack5
│ │ ├── host.test.js.snap.webpack5
│ │ ├── hot-and-live-reload.test.js.snap.webpack5
│ │ ├── ipc.test.js.snap.webpack5
│ │ ├── logging.test.js.snap.webpack5
│ │ ├── mime-types.test.js.snap.webpack5
│ │ ├── module-federation.test.js.snap.webpack5
│ │ ├── multi-compiler.test.js.snap.webpack5
│ │ ├── on-listening.test.js.snap.webpack5
│ │ ├── overlay.test.js.snap.webpack5
│ │ ├── port.test.js.snap.webpack5
│ │ ├── server-and-client-transport.test.js.snap.webpack5
│ │ ├── server.test.js.snap.webpack5
│ │ ├── setup-exit-signals.test.js.snap.webpack5
│ │ ├── setup-middlewares.test.js.snap.webpack5
│ │ ├── static-directory.test.js.snap.webpack5
│ │ ├── static-public-path.test.js.snap.webpack5
│ │ ├── stats.test.js.snap.webpack5
│ │ ├── target.test.js.snap.webpack5
│ │ ├── watch-files.test.js.snap.webpack5
│ │ ├── web-socket-communication.test.js.snap.webpack5
│ │ ├── web-socket-server-url.test.js.snap.webpack5
│ │ └── web-socket-server.test.js.snap.webpack5
│ ├── allowed-hosts.test.js
│ ├── api.test.js
│ ├── app.test.js
│ ├── bonjour.test.js
│ ├── built-in-routes.test.js
│ ├── client-reconnect.test.js
│ ├── client.test.js
│ ├── compress.test.js
│ ├── entry.test.js
│ ├── headers.test.js
│ ├── history-api-fallback.test.js
│ ├── host.test.js
│ ├── hot-and-live-reload.test.js
│ ├── ipc.test.js
│ ├── lazy-compilation.test.js
│ ├── logging.test.js
│ ├── mime-types.test.js
│ ├── module-federation.test.js
│ ├── multi-compiler.test.js
│ ├── on-listening.test.js
│ ├── overlay.test.js
│ ├── port.test.js
│ ├── progress.test.js
│ ├── range-header.test.js
│ ├── server-and-client-transport.test.js
│ ├── server.test.js
│ ├── setup-exit-signals.test.js
│ ├── setup-middlewares.test.js
│ ├── static-directory.test.js
│ ├── static-public-path.test.js
│ ├── stats.test.js
│ ├── target.test.js
│ ├── watch-files.test.js
│ ├── web-socket-communication.test.js
│ ├── web-socket-server-url.test.js
│ └── web-socket-server.test.js
├── fixtures
│ ├── client-config
│ │ ├── bar.js
│ │ ├── foo.js
│ │ ├── index.html
│ │ ├── static
│ │ │ └── foo.txt
│ │ └── webpack.config.js
│ ├── custom-client
│ │ ├── CustomClientEntry.js
│ │ ├── CustomClientHotEntry.js
│ │ └── CustomSockJSClient.js
│ ├── historyapifallback-2-config
│ │ ├── bar.html
│ │ ├── foo.js
│ │ ├── other.html
│ │ ├── random-file.txt
│ │ └── webpack.config.js
│ ├── historyapifallback-3-config
│ │ ├── bar.html
│ │ ├── foo.js
│ │ ├── index.html
│ │ └── webpack.config.js
│ ├── historyapifallback-config
│ │ ├── bar.html
│ │ ├── foo.js
│ │ ├── index.html
│ │ └── webpack.config.js
│ ├── https-certificate
│ │ ├── ca-symlink.pem
│ │ ├── ca.pem
│ │ ├── server-symlink.crt
│ │ ├── server-symlink.key
│ │ ├── server-symlink.pfx
│ │ ├── server.crt
│ │ ├── server.key
│ │ └── server.pfx
│ ├── lazy-compilation-multiple-entries
│ │ ├── one.js
│ │ ├── two.js
│ │ └── webpack.config.js
│ ├── lazy-compilation-single-entry
│ │ ├── entry.js
│ │ └── webpack.config.js
│ ├── mime-types-config
│ │ ├── file.custom
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── module-federation-config
│ │ ├── entry1.js
│ │ ├── entry2.js
│ │ ├── webpack.config.js
│ │ ├── webpack.multi.config.js
│ │ ├── webpack.object-entry.config.js
│ │ └── webpack.plugin.js
│ ├── multi-compiler-one-configuration
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── multi-compiler-two-configurations
│ │ ├── one.js
│ │ ├── two.js
│ │ └── webpack.config.js
│ ├── multi-public-path-config
│ │ ├── bar.js
│ │ ├── baz.js
│ │ ├── foo.js
│ │ ├── test.html
│ │ └── webpack.config.js
│ ├── overlay-config
│ │ ├── foo.js
│ │ ├── trusted-types.webpack.config.js
│ │ └── webpack.config.js
│ ├── provide-plugin-custom
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── provide-plugin-default
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── provide-plugin-sockjs-config
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── provide-plugin-ws-config
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── reload-config-2
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── reload-config
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── simple-config-other
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── simple-config
│ │ ├── foo.js
│ │ └── webpack.config.js
│ ├── ssl
│ │ ├── localhost-cert.pem
│ │ └── localhost-privkey.pem
│ ├── static-config
│ │ ├── foo.js
│ │ ├── other
│ │ │ └── foo.html
│ │ ├── public
│ │ │ ├── assets
│ │ │ │ ├── example.txt
│ │ │ │ └── other.txt
│ │ │ ├── bar
│ │ │ │ └── index.html
│ │ │ ├── foo.wasm
│ │ │ ├── index.html
│ │ │ ├── node_modules
│ │ │ │ ├── .gitkeep
│ │ │ │ └── index.html
│ │ │ └── other.html
│ │ ├── static
│ │ │ └── index.html
│ │ └── webpack.config.js
│ ├── universal-compiler-config
│ │ ├── browser.js
│ │ ├── server.js
│ │ └── webpack.config.js
│ ├── watch-files-config
│ │ ├── foo.js
│ │ ├── other
│ │ │ └── foo.html
│ │ ├── public
│ │ │ ├── assets
│ │ │ │ ├── example.txt
│ │ │ │ ├── non-exist.txt
│ │ │ │ └── other.txt
│ │ │ ├── bar
│ │ │ │ └── index.html
│ │ │ └── other.html
│ │ ├── static
│ │ │ └── index.html
│ │ └── webpack.config.js
│ ├── worker-config-dev-server-false
│ │ ├── index.js
│ │ ├── public
│ │ │ └── worker-bundle.js
│ │ ├── webpack.config.js
│ │ └── worker.js
│ └── worker-config
│ │ ├── index.js
│ │ ├── webpack.config.js
│ │ └── worker.js
├── helpers
│ ├── conditional-test.js
│ ├── custom-http.js
│ ├── get-port.js
│ ├── global-setup-test.js
│ ├── html-generator-plugin.js
│ ├── normalize-options.js
│ ├── normalize.js
│ ├── ports-map.js
│ ├── puppeteer-constants.js
│ ├── run-browser.js
│ ├── sequencer.js
│ ├── session-subscribe.js
│ ├── setup-test.js
│ ├── snapshot-resolver.js
│ ├── test-server.js
│ └── trusted-types-html-generator-plugin.js
├── normalizeOptions.test.ts
├── placeholder.js
├── placeholder1.js
└── tsconfig.json
├── tsconfig.build.json
├── tsconfig.client.json
└── tsconfig.json
/.github/renovate.json5:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3 | "extends": ["config:base", "schedule:monthly", "group:allNonMajor"],
4 | "rangeStrategy": "bump",
5 | "packageRules": [{ "depTypeList": ["peerDependencies"], "enabled": false }]
6 | }
7 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Release Full
3 |
4 | on:
5 | workflow_dispatch:
6 | inputs:
7 | version:
8 | type: choice
9 | description: "Release Version Type"
10 | required: true
11 | default: "patch"
12 | options:
13 | - major
14 | - premajor
15 | - minor
16 | - preminor
17 | - patch
18 | - prepatch
19 | - prerelease
20 |
21 | tag:
22 | type: choice
23 | description: "Release Npm Tag"
24 | required: true
25 | default: "latest"
26 | options:
27 | - canary
28 | - nightly
29 | - latest
30 | - beta
31 | - alpha
32 |
33 | dry_run:
34 | type: boolean
35 | description: "DryRun release"
36 | required: true
37 | default: false
38 |
39 | permissions:
40 | # To publish packages with provenance
41 | id-token: write
42 |
43 | jobs:
44 | release:
45 | name: Release
46 | permissions:
47 | contents: write
48 | # To publish packages with provenance
49 | id-token: write
50 | runs-on: ubuntu-latest
51 |
52 | steps:
53 | - name: Checkout
54 | uses: actions/checkout@v4
55 |
56 | - name: Install Pnpm
57 | run: |
58 | npm install -g corepack@latest
59 | corepack enable
60 |
61 | - name: Setup Node.js
62 | uses: actions/setup-node@v4
63 | with:
64 | node-version: 20
65 | cache: "pnpm"
66 |
67 | - name: Install Dependencies
68 | run: pnpm install
69 |
70 | - name: Run Test
71 | run: pnpm run test
72 |
73 | - name: Try release to npm
74 | run: pnpm run release
75 | env:
76 | DRY_RUN: ${{ inputs.dry_run }}
77 | TAG: ${{ inputs.tag }}
78 | VERSION: ${{ inputs.version }}
79 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
80 |
81 |
82 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | # Controls when the action will run.
4 | on:
5 | # Triggers the workflow on pull request events but only for the main branch
6 | pull_request:
7 | branches: [main]
8 | push:
9 | branches: [main]
10 | # Allows you to run this workflow manually from the Actions tab
11 | workflow_dispatch:
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 | test:
16 | name: Test - ${{ matrix.os }} - Node v${{ matrix.node }})
17 |
18 | strategy:
19 | matrix:
20 | os: [ubuntu-latest, windows-latest, macos-latest]
21 | node: [18.x]
22 |
23 | runs-on: ${{ matrix.os }}
24 |
25 | concurrency:
26 | group: test-${{ matrix.os }}-v${{ matrix.node }}-${{ github.ref }}
27 | cancel-in-progress: true
28 |
29 | # Steps represent a sequence of tasks that will be executed as part of the job
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v4
33 |
34 | - name: Install Pnpm
35 | run: |
36 | npm install -g corepack@latest
37 | corepack enable
38 |
39 | - name: Setup Node.js
40 | uses: actions/setup-node@v4
41 | with:
42 | node-version: ${{ matrix.node }}
43 | cache: "pnpm"
44 |
45 | - name: Install Dependencies
46 | run: pnpm install
47 |
48 | - name: Run Test
49 | run: pnpm run test
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local
2 | .DS_Store
3 | *.local
4 | *.log*
5 | *.tsbuildinfo
6 |
7 | # Dist
8 | node_modules
9 | dist/
10 | client/
11 | test-results
12 |
13 | # Test
14 | tests/js/
15 | !tests/**/node_modules
16 |
17 | # IDE
18 | .vscode/*
19 | !.vscode/settings.json
20 | !.vscode/extensions.json
21 | .idea
22 | *.tsbuildinfo
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org/
2 |
3 | # The package of the same name conflicts with node:buffer and it will affect our ci results. https://www.npmjs.com/package/buffer
4 | hoist-pattern[]=!buffer
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "streetsidesoftware.code-spell-checker",
4 | "tamasfe.even-better-toml",
5 | "rust-lang.rust-analyzer",
6 | "fabiospampinato.vscode-debug-launcher"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "search.useIgnoreFiles": true,
3 | "[json]": {
4 | "editor.defaultFormatter": "biomejs.biome"
5 | },
6 | "[typescript]": {
7 | "editor.defaultFormatter": "biomejs.biome"
8 | },
9 | "[javascript]": {
10 | "editor.defaultFormatter": "biomejs.biome"
11 | },
12 | "[javascriptreact]": {
13 | "editor.defaultFormatter": "biomejs.biome"
14 | },
15 | "[css]": {
16 | "editor.defaultFormatter": "biomejs.biome"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @rspack/dev-server
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-present Bytedance, Inc. and its affiliates.
4 |
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | # @rspack/dev-server
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Use Rspack with a development server that provides live reloading. This should be used for development only.
16 |
17 | > `@rspack/dev-server` is based on `webpack-dev-server@5`
18 |
19 | ## Installation
20 |
21 | First of all, install `@rspack/dev-server` and `@rspack/core` by your favorite package manager:
22 |
23 | ```bash
24 | # npm
25 | $ npm install @rspack/dev-server @rspack/core --save-dev
26 |
27 | # yarn
28 | $ yarn add @rspack/dev-server @rspack/core --dev
29 |
30 | # pnpm
31 | $ pnpm add @rspack/dev-server @rspack/core --save-dev
32 |
33 | # bun
34 | $ bun add @rspack/dev-server @rspack/core -D
35 | ```
36 |
37 | ## Usage
38 |
39 | There are two recommended ways to use `@rspack/dev-server`:
40 |
41 | ### With the CLI
42 |
43 | The easiest way to use it is with the [`@rspack/cli`](https://www.npmjs.com/package/@rspack/cli).
44 |
45 | You can install it in your project by:
46 |
47 | ```bash
48 | # npm
49 | $ npm install @rspack/cli --save-dev
50 |
51 | # yarn
52 | $ yarn add @rspack/cli --dev
53 |
54 | # pnpm
55 | $ pnpm add @rspack/cli --save-dev
56 |
57 | # bun
58 | $ bun add @rspack/cli -D
59 | ```
60 |
61 | And then start the development server by:
62 |
63 | ```bash
64 | # with rspack.config.js
65 | $ rspack serve
66 |
67 | # with custom config file
68 | $ rspack serve -c ./your.config.js
69 | ```
70 |
71 | > See [CLI](https://rspack.dev/api/cli) for more details.
72 |
73 | While starting the development server, you can specify the configuration by the `devServer` field of your Rspack config file:
74 |
75 | ```js
76 | // rspack.config.js
77 | module.exports = {
78 | // ...
79 | devServer: {
80 | // the configuration of the development server
81 | port: 8080
82 | },
83 | };
84 | ```
85 |
86 | > See [DevServer](https://rspack.dev/config/dev-server) for all configuration options.
87 |
88 | ### With the API
89 |
90 | While it's recommended to run `@rspack/dev-server` via the CLI, you may also choose to start a server via the API.
91 |
92 | ```js
93 | import { RspackDevServer } from "@rspack/dev-server";
94 | import rspack from "@rspack/core";
95 | import rspackConfig from './rspack.config.js';
96 |
97 | const compiler = rspack(rspackConfig);
98 | const devServerOptions = {
99 | ...rspackConfig.devServer,
100 | // override
101 | port: 8888
102 | };
103 |
104 | const server = new RspackDevServer(devServerOptions, compiler);
105 |
106 | server.startCallback(() => {
107 | console.log('Successfully started server on http://localhost:8888');
108 | });
109 | ```
110 |
111 | > Cause `@rspack/dev-server` is based on `webpack-dev-server@5`, you can see the [webpack-dev-server API](https://webpack.js.org/api/webpack-dev-server/) for more methods of the server instance.
112 |
113 | ## Credits
114 |
115 | Thanks to the [webpack-dev-server](https://github.com/webpack/webpack-dev-server) project created by [@sokra](https://github.com/sokra)
116 |
117 | ## License
118 |
119 | [MIT licensed](https://github.com/web-infra-dev/rspack-dev-server/blob/main/LICENSE).
120 |
--------------------------------------------------------------------------------
/biome.jsonc:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
3 | "files": {
4 | "ignore": [
5 | "client-src/**/*",
6 | "client/**/*.js",
7 | "dist/**/*",
8 | "tests/fixtures/**/*"
9 | ]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | const os = require("node:os");
2 | const isWin = os.platform() === "win32";
3 | /** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */
4 | const config = {
5 | preset: "ts-jest",
6 | testEnvironmentOptions: {
7 | url: "http://localhost/",
8 | },
9 | testMatch: [
10 | "/tests/*.test.ts",
11 | // TODO: enable after migrating to separated repo
12 | "/tests/e2e/*.test.js",
13 | ],
14 | testPathIgnorePatterns: [
15 | // TODO: check why http proxy server throw error with websocket server
16 | "/tests/e2e/allowed-hosts.test.js",
17 | // TODO: check why this test timeout
18 | "/tests/e2e/host.test.js",
19 | // TODO: check why this test throw error when run with other tests
20 | "/tests/e2e/watch-files.test.js",
21 | // TODO: check why this test timeout
22 | "/tests/e2e/web-socket-server-url.test.js",
23 | ],
24 | cache: false,
25 | testTimeout: process.env.CI ? 120000 : 30000,
26 | transform: {
27 | "(.*)\\.{js,ts}": [
28 | "ts-jest",
29 | {
30 | tsconfig: "/tests/tsconfig.json",
31 | },
32 | ],
33 | },
34 | // Add this to find out which test timeouts
35 | // testSequencer: "/tests/helpers/sequencer.js",
36 | snapshotResolver: "/tests/helpers/snapshot-resolver.js",
37 | setupFilesAfterEnv: ["/tests/helpers/setup-test.js"],
38 | globalSetup: "/tests/helpers/global-setup-test.js",
39 | moduleNameMapper: {
40 | "^uuid$": require.resolve("uuid"),
41 | },
42 | };
43 |
44 | module.exports = config;
45 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@rspack/dev-server",
3 | "version": "1.1.3",
4 | "license": "MIT",
5 | "description": "Development server for rspack",
6 | "main": "./dist/index.js",
7 | "types": "./dist/index.d.ts",
8 | "publishConfig": {
9 | "access": "public",
10 | "registry": "https://registry.npmjs.org/",
11 | "provenance": true
12 | },
13 | "exports": {
14 | ".": {
15 | "default": "./dist/index.js"
16 | },
17 | "./client/*": "./client/*.js",
18 | "./client/*.js": "./client/*.js",
19 | "./package.json": "./package.json"
20 | },
21 | "scripts": {
22 | "build": "pnpm run build:server && pnpm run build:client",
23 | "build:server": "tsc -b ./tsconfig.build.json",
24 | "build:client": "tsc -b ./tsconfig.client.json",
25 | "dev": "tsc -b -w",
26 | "lint": "biome check .",
27 | "lint:write": "biome check . --write",
28 | "format": "node ./node_modules/prettier/bin/prettier.cjs \"packages/**/src/**/*.{ts,tsx,js}\" \"crates/rspack_plugin_runtime/**/*.{ts,js}\" \"x.mjs\" --check",
29 | "test:install": "cross-env ./node_modules/.bin/puppeteer browsers install chrome",
30 | "test": "pnpm run test:install && pnpm run build && cross-env NO_COLOR=1 node --expose-gc --max-old-space-size=8192 --experimental-vm-modules ./node_modules/jest-cli/bin/jest --colors",
31 | "release": "node ./scripts/release.mjs"
32 | },
33 | "simple-git-hooks": {
34 | "pre-commit": "npx nano-staged"
35 | },
36 | "nano-staged": {
37 | "*.{js,jsx,ts,tsx,mjs,cjs}": [
38 | "biome check --write --no-errors-on-unmatched"
39 | ]
40 | },
41 | "files": [
42 | "dist",
43 | "client"
44 | ],
45 | "engines": {
46 | "node": ">= 18.12.0"
47 | },
48 | "packageManager": "pnpm@9.6.0",
49 | "homepage": "https://rspack.dev",
50 | "bugs": "https://github.com/web-infra-dev/rspack-dev-server/issues",
51 | "repository": {
52 | "type": "git",
53 | "url": "https://github.com/web-infra-dev/rspack-dev-server"
54 | },
55 | "devDependencies": {
56 | "@biomejs/biome": "^1.8.3",
57 | "@jest/reporters": "29.7.0",
58 | "@jest/test-sequencer": "^29.7.0",
59 | "@rspack/core": "1.3.11",
60 | "@rspack/plugin-react-refresh": "1.0.0",
61 | "@types/express": "4.17.21",
62 | "@types/jest": "29.5.12",
63 | "@types/mime-types": "2.1.4",
64 | "@types/ws": "8.5.10",
65 | "@hono/node-server": "^1.13.3",
66 | "cross-env": "^7.0.3",
67 | "css-loader": "^7.1.2",
68 | "connect": "^3.7.0",
69 | "execa": "9.3.0",
70 | "fs-extra": "11.2.0",
71 | "graceful-fs": "4.2.10",
72 | "http-proxy": "^1.18.1",
73 | "hono": "^4.6.8",
74 | "jest": "29.7.0",
75 | "jest-cli": "29.7.0",
76 | "jest-environment-node": "29.7.0",
77 | "jest-serializer-path": "^0.1.15",
78 | "nano-staged": "^0.8.0",
79 | "prettier": "3.2.5",
80 | "puppeteer": "^23.2.2",
81 | "react-refresh": "0.14.0",
82 | "require-from-string": "^2.0.2",
83 | "semver": "7.6.3",
84 | "simple-git-hooks": "^2.11.1",
85 | "sockjs-client": "^1.6.1",
86 | "style-loader": "^3.3.3",
87 | "supertest": "^6.1.3",
88 | "tcp-port-used": "^1.0.2",
89 | "ts-jest": "29.1.2",
90 | "typescript": "5.0.2",
91 | "wait-for-expect": "^3.0.2",
92 | "webpack": "^5.94.0",
93 | "webpack-dev-middleware": "^7.4.2",
94 | "express": "^4.21.2"
95 | },
96 | "dependencies": {
97 | "chokidar": "^3.6.0",
98 | "http-proxy-middleware": "^2.0.9",
99 | "p-retry": "^6.2.0",
100 | "webpack-dev-server": "5.2.2",
101 | "ws": "^8.18.0"
102 | },
103 | "peerDependencies": {
104 | "@rspack/core": "*"
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/scripts/patch-node-env.cjs:
--------------------------------------------------------------------------------
1 | // Copied from
2 | //
3 | const NodeEnvironment =
4 | // For jest@29
5 | require("jest-environment-node").TestEnvironment ||
6 | // For jest@27
7 | require("jest-environment-node");
8 |
9 | class CustomEnvironment extends NodeEnvironment {
10 | // Workaround for `Symbol('JEST_STATE_SYMBOL')`
11 | async handleTestEvent(event, state) {
12 | if (!this.global.JEST_STATE_SYMBOL) {
13 | this.global.JEST_STATE_SYMBOL = state;
14 | }
15 | }
16 | }
17 |
18 | module.exports = CustomEnvironment;
19 |
--------------------------------------------------------------------------------
/scripts/release.mjs:
--------------------------------------------------------------------------------
1 | import path from "node:path";
2 | import * as url from "node:url";
3 | import { $ } from "execa";
4 | import fs from "fs-extra";
5 | import { inc } from "semver";
6 |
7 | const RELEASE_TAG = process.env.TAG || "beta";
8 | const RELEASE_DRY_RUN = process.env.DRY_RUN || "true";
9 | const RELEASE_VERSION_TYPE = process.env.VERSION || "prerelease";
10 | const RELEASE_NPM_TOKEN = process.env.NPM_TOKEN || "";
11 |
12 | const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
13 | const PKG_PATH = path.resolve(__dirname, "../package.json");
14 | const pkg = fs.readJsonSync(PKG_PATH);
15 | const currentVersion = pkg.version;
16 | const nextVersion = inc(currentVersion, RELEASE_VERSION_TYPE);
17 | if (!nextVersion) {
18 | throw new Error(
19 | `Failed to generate next version from "${currentVersion}" with type "${RELEASE_VERSION_TYPE}"`,
20 | );
21 | }
22 |
23 | console.info(`Release ${RELEASE_TAG} version ${nextVersion}`);
24 |
25 | // Update pkg version
26 | console.info(`Updating version from ${currentVersion} to ${nextVersion}`);
27 | pkg.version = nextVersion;
28 | fs.writeJsonSync(PKG_PATH, pkg, { spaces: 2 });
29 |
30 | // Write npmrc
31 | const npmrcPath = `${process.env.HOME}/.npmrc`;
32 | console.info(`Writing npmrc to ${npmrcPath}`);
33 | fs.writeFileSync(
34 | npmrcPath,
35 | `//registry.npmjs.org/:_authToken=${RELEASE_NPM_TOKEN}`,
36 | );
37 |
38 | // Publish to npm
39 | console.info(`Publishing to npm with tag ${RELEASE_TAG}`);
40 | const dryRun = RELEASE_DRY_RUN === "true" ? ["--dry-run"] : [];
41 | try {
42 | await $`pnpm publish ${dryRun} --tag ${RELEASE_TAG} --no-git-checks --provenance`;
43 | console.info("Published successfully");
44 | } catch (e) {
45 | console.error(`Publish failed: ${e.message}`);
46 | process.exit(1);
47 | } finally {
48 | fs.removeSync(npmrcPath);
49 | }
50 |
51 | // Push tag to github
52 | if (RELEASE_DRY_RUN !== "true") {
53 | console.info("Pushing tag to github");
54 | const tagName = `v${nextVersion}`;
55 | try {
56 | await $`git config --global --add safe.directory /github/workspace`;
57 | await $`git config --global user.name "github-actions[bot]"`;
58 | await $`git config --global user.email "github-actions[bot]@users.noreply.github.com"`;
59 | await $`git status`;
60 | await $`git tag ${tagName}`;
61 | await $`git push origin ${tagName}`;
62 | console.info("Pushed tag successfully");
63 | } catch (e) {
64 | console.error(`Push tag failed: ${e.message}`);
65 | process.exit(1);
66 | }
67 |
68 | try {
69 | await $`git add --all`;
70 | const commitMsg = `release ${tagName}`;
71 | await $`git commit -m ${commitMsg}`;
72 | await $`git push`;
73 | console.info("Pushed branch successfully");
74 | } catch (e) {
75 | console.error(`Update branch failed: ${e.message}`);
76 | process.exit(1);
77 | }
78 | }
79 |
80 | console.info("Release completed");
81 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | import type { DevServer } from "@rspack/core";
2 | import type WebpackDevServer from "webpack-dev-server";
3 |
4 | export type { DevServer };
5 |
6 | export interface ResolvedDevServer extends DevServer {
7 | port: number | string;
8 | static: false | Array;
9 | devMiddleware: DevServer["devMiddleware"];
10 | hot: boolean | "only";
11 | host?: string;
12 | open: WebpackDevServer.Open[];
13 | magicHtml: boolean;
14 | liveReload: boolean;
15 | webSocketServer: false | WebpackDevServer.WebSocketServerConfiguration;
16 | proxy: Required;
17 | client: WebpackDevServer.ClientConfiguration;
18 | allowedHosts: "auto" | string[] | "all";
19 | bonjour: false | Record | WebpackDevServer.BonjourOptions;
20 | compress: boolean;
21 | historyApiFallback: false | WebpackDevServer.ConnectHistoryApiFallbackOptions;
22 | server: WebpackDevServer.ServerConfiguration;
23 | ipc: string | undefined;
24 | setupExitSignals: boolean;
25 | watchFiles: WebpackDevServer.WatchFiles[];
26 | }
27 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { RspackDevServer } from "./server";
2 | export type { DevServer as Configuration } from "@rspack/core";
3 |
--------------------------------------------------------------------------------
/src/patch.ts:
--------------------------------------------------------------------------------
1 | import WebpackDevServer from "webpack-dev-server";
2 |
3 | let old: InstanceType["sendStats"] | undefined;
4 |
5 | function restoreDevServerPatch() {
6 | // @ts-expect-error private API
7 | WebpackDevServer.prototype.sendStats = old;
8 | }
9 |
10 | // Patch webpack-dev-server to prevent it from failing to send stats.
11 | // See https://github.com/web-infra-dev/rspack/pull/4028 for details.
12 | function applyDevServerPatch() {
13 | if (old) return restoreDevServerPatch;
14 |
15 | // @ts-expect-error private API
16 | old = WebpackDevServer.prototype.sendStats;
17 |
18 | // @ts-expect-error private API
19 | WebpackDevServer.prototype.sendStats = function sendStats__rspack_patched(
20 | // @ts-expect-error
21 | ...args
22 | ) {
23 | const stats = args[1];
24 |
25 | if (!stats) {
26 | return;
27 | }
28 |
29 | return old.apply(this, args);
30 | };
31 |
32 | return restoreDevServerPatch;
33 | }
34 |
35 | export { applyDevServerPatch };
36 |
--------------------------------------------------------------------------------
/src/server.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * The following code is modified based on
3 | * https://github.com/webpack/webpack-dev-server/blob/b0f15ace0123c125d5870609ef4691c141a6d187/lib/Server.js
4 | *
5 | * MIT Licensed
6 | * Author Tobias Koppers @sokra
7 | * Copyright (c) JS Foundation and other contributors
8 | * https://github.com/webpack/webpack-dev-server/blob/b0f15ace0123c125d5870609ef4691c141a6d187/LICENSE
9 | */
10 | import type { Server } from "node:http";
11 | import type { Socket } from "node:net";
12 | import { type Compiler, MultiCompiler } from "@rspack/core";
13 | import type { FSWatcher } from "chokidar";
14 | import WebpackDevServer from "webpack-dev-server";
15 | // @ts-ignore 'package.json' is not under 'rootDir'
16 | import { version } from "../package.json";
17 |
18 | import type { DevServer, ResolvedDevServer } from "./config";
19 | import { applyDevServerPatch } from "./patch";
20 |
21 | applyDevServerPatch();
22 |
23 | const getFreePort = async function getFreePort(port: string, host: string) {
24 | if (typeof port !== "undefined" && port !== null && port !== "auto") {
25 | return port;
26 | }
27 |
28 | const { default: pRetry } = await import("p-retry");
29 | const getPort = require("webpack-dev-server/lib/getPort");
30 | const basePort =
31 | typeof process.env.WEBPACK_DEV_SERVER_BASE_PORT !== "undefined"
32 | ? Number.parseInt(process.env.WEBPACK_DEV_SERVER_BASE_PORT, 10)
33 | : 8080;
34 |
35 | // Try to find unused port and listen on it for 3 times,
36 | // if port is not specified in options.
37 | const defaultPortRetry =
38 | typeof process.env.WEBPACK_DEV_SERVER_PORT_RETRY !== "undefined"
39 | ? Number.parseInt(process.env.WEBPACK_DEV_SERVER_PORT_RETRY, 10)
40 | : 3;
41 |
42 | return pRetry(() => getPort(basePort, host), {
43 | retries: defaultPortRetry,
44 | });
45 | };
46 |
47 | WebpackDevServer.getFreePort = getFreePort;
48 |
49 | export class RspackDevServer extends WebpackDevServer {
50 | static getFreePort = getFreePort;
51 | /**
52 | * resolved after `normalizedOptions`
53 | */
54 | /** @ts-ignore: types of path data of rspack is not compatible with webpack */
55 | declare options: ResolvedDevServer;
56 |
57 | declare staticWatchers: FSWatcher[];
58 |
59 | declare sockets: Socket[];
60 |
61 | declare server: Server;
62 | // TODO: remove @ts-ignore here
63 | /** @ts-ignore */
64 | public compiler: Compiler | MultiCompiler;
65 | public webSocketServer:
66 | | WebpackDevServer.WebSocketServerImplementation
67 | | undefined;
68 | static version: string = version;
69 |
70 | constructor(options: DevServer, compiler: Compiler | MultiCompiler) {
71 | // biome-ignore lint/suspicious/noExplicitAny: _
72 | super(options as WebpackDevServer.Configuration, compiler as any);
73 | // override
74 | }
75 |
76 | async initialize() {
77 | const compilers =
78 | this.compiler instanceof MultiCompiler
79 | ? this.compiler.compilers
80 | : [this.compiler];
81 |
82 | for (const compiler of compilers) {
83 | const mode = compiler.options.mode || process.env.NODE_ENV;
84 | if (this.options.hot) {
85 | if (mode === "production") {
86 | this.logger.warn(
87 | "Hot Module Replacement (HMR) is enabled for the production build. \n" +
88 | "Make sure to disable HMR for production by setting `devServer.hot` to `false` in the configuration.",
89 | );
90 | }
91 |
92 | compiler.options.resolve.alias = {
93 | "ansi-html-community": require.resolve(
94 | "@rspack/dev-server/client/utils/ansiHTML",
95 | ),
96 | ...compiler.options.resolve.alias,
97 | };
98 | }
99 | }
100 |
101 | // @ts-expect-error
102 | await super.initialize();
103 | }
104 |
105 | getClientEntry(): string {
106 | return require.resolve("@rspack/dev-server/client/index");
107 | }
108 |
109 | getClientHotEntry(): string | undefined {
110 | if (this.options.hot === "only") {
111 | return require.resolve("@rspack/core/hot/only-dev-server");
112 | }
113 | if (this.options.hot) {
114 | return require.resolve("@rspack/core/hot/dev-server");
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/tests/ansiHTML.test.ts:
--------------------------------------------------------------------------------
1 | import ansiHTML from "../client-src/utils/ansiHTML";
2 |
3 | describe("ansi-html", () => {
4 | it("should transform 24-bit rgb ansi colors", () => {
5 | expect(ansiHTML("\u001b[38;2;255;30;30m×\u001b[0m")).toMatchInlineSnapshot(
6 | `"× "`,
7 | );
8 | });
9 |
10 | it("should transform 24-bit rgb ansi colors with additional properties", () => {
11 | expect(
12 | ansiHTML("[\u001b[38;2;92;157;255;1;4m/root/index.js\u001b[0m:1:1]"),
13 | ).toMatchInlineSnapshot(
14 | `"[/root/index.js :1:1] "`,
15 | );
16 | });
17 |
18 | it("should transform basic ansi colors", () => {
19 | expect(ansiHTML("\u001b[0mcontent")).toMatchInlineSnapshot(
20 | `"content "`,
21 | );
22 | expect(
23 | ansiHTML(
24 | "\u001b[33m<\u001b[39m\u001b[33mheader\u001b[39m\u001b[33m>\u001b[39m",
25 | ),
26 | ).toMatchInlineSnapshot(
27 | `"< header > "`,
28 | );
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/bonjour.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`bonjour option as object should apply bonjour options: console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`bonjour option as object should apply bonjour options: page errors 1`] = `[]`;
12 |
13 | exports[`bonjour option as object should apply bonjour options: response status 1`] = `200`;
14 |
15 | exports[`bonjour option as true should call bonjour with correct params: console messages 1`] = `
16 | [
17 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
18 | "[HMR] Waiting for update signal from WDS...",
19 | "Hey.",
20 | ]
21 | `;
22 |
23 | exports[`bonjour option as true should call bonjour with correct params: page errors 1`] = `[]`;
24 |
25 | exports[`bonjour option as true should call bonjour with correct params: response status 1`] = `200`;
26 |
27 | exports[`bonjour option bonjour object and 'server' option should apply bonjour options: console messages 1`] = `
28 | [
29 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
30 | "[HMR] Waiting for update signal from WDS...",
31 | "Hey.",
32 | ]
33 | `;
34 |
35 | exports[`bonjour option bonjour object and 'server' option should apply bonjour options: page errors 1`] = `[]`;
36 |
37 | exports[`bonjour option bonjour object and 'server' option should apply bonjour options: response status 1`] = `200`;
38 |
39 | exports[`bonjour option with 'server' option should call bonjour with 'https' type: console messages 1`] = `
40 | [
41 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
42 | "[HMR] Waiting for update signal from WDS...",
43 | "Hey.",
44 | ]
45 | `;
46 |
47 | exports[`bonjour option with 'server' option should call bonjour with 'https' type: page errors 1`] = `[]`;
48 |
49 | exports[`bonjour option with 'server' option should call bonjour with 'https' type: response status 1`] = `200`;
50 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/built-in-routes.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: console messages 1`] = `[]`;
4 |
5 | exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: directory list 1`] = `
6 | "Assets Report: "
15 | `;
16 |
17 | exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: page errors 1`] = `[]`;
18 |
19 | exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: response headers content-type 1`] = `"text/html; charset=utf-8"`;
20 |
21 | exports[`Built in routes with multi config should handle GET request to directory index and list all middleware directories: response status 1`] = `200`;
22 |
23 | exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: console messages 1`] = `[]`;
24 |
25 | exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: directory list 1`] = `
26 | "Assets Report: "
33 | `;
34 |
35 | exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: page errors 1`] = `[]`;
36 |
37 | exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: response headers content-type 1`] = `"text/html; charset=utf-8"`;
38 |
39 | exports[`Built in routes with simple config should handle GET request to directory index and list all middleware directories: response status 1`] = `200`;
40 |
41 | exports[`Built in routes with simple config should handle GET request to invalidate endpoint: console messages 1`] = `[]`;
42 |
43 | exports[`Built in routes with simple config should handle GET request to invalidate endpoint: page errors 1`] = `[]`;
44 |
45 | exports[`Built in routes with simple config should handle GET request to invalidate endpoint: response status 1`] = `200`;
46 |
47 | exports[`Built in routes with simple config should handle GET request to magic async chunk: console messages 1`] = `[]`;
48 |
49 | exports[`Built in routes with simple config should handle GET request to magic async chunk: response headers content-type 1`] = `"application/javascript; charset=utf-8"`;
50 |
51 | exports[`Built in routes with simple config should handle GET request to magic async chunk: response status 1`] = `200`;
52 |
53 | exports[`Built in routes with simple config should handle HEAD request to directory index: console messages 1`] = `[]`;
54 |
55 | exports[`Built in routes with simple config should handle HEAD request to directory index: directory list 1`] = `""`;
56 |
57 | exports[`Built in routes with simple config should handle HEAD request to directory index: page errors 1`] = `[]`;
58 |
59 | exports[`Built in routes with simple config should handle HEAD request to directory index: response headers content-type 1`] = `"text/html; charset=utf-8"`;
60 |
61 | exports[`Built in routes with simple config should handle HEAD request to directory index: response status 1`] = `200`;
62 |
63 | exports[`Built in routes with simple config should handle HEAD request to magic async chunk: console messages 1`] = `[]`;
64 |
65 | exports[`Built in routes with simple config should handle HEAD request to magic async chunk: response headers content-type 1`] = `"application/javascript; charset=utf-8"`;
66 |
67 | exports[`Built in routes with simple config should handle HEAD request to magic async chunk: response status 1`] = `200`;
68 |
69 | exports[`Built in routes with simple config should handles GET request to sockjs bundle: console messages 1`] = `[]`;
70 |
71 | exports[`Built in routes with simple config should handles GET request to sockjs bundle: page errors 1`] = `[]`;
72 |
73 | exports[`Built in routes with simple config should handles GET request to sockjs bundle: response headers content-type 1`] = `"application/javascript; charset=UTF-8"`;
74 |
75 | exports[`Built in routes with simple config should handles GET request to sockjs bundle: response status 1`] = `200`;
76 |
77 | exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: console messages 1`] = `[]`;
78 |
79 | exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: page errors 1`] = `[]`;
80 |
81 | exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: response headers content-type 1`] = `"application/javascript; charset=UTF-8"`;
82 |
83 | exports[`Built in routes with simple config should handles HEAD request to sockjs bundle: response status 1`] = `200`;
84 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/client-reconnect.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`client.reconnect option specified as false should not try to reconnect: console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | "[webpack-dev-server] Disconnected!",
9 | ]
10 | `;
11 |
12 | exports[`client.reconnect option specified as false should not try to reconnect: page errors 1`] = `[]`;
13 |
14 | exports[`client.reconnect option specified as false should not try to reconnect: response status 1`] = `200`;
15 |
16 | exports[`client.reconnect option specified as number should try to reconnect 2 times: console messages 1`] = `
17 | [
18 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
19 | "[HMR] Waiting for update signal from WDS...",
20 | "Hey.",
21 | "[webpack-dev-server] Disconnected!",
22 | "[webpack-dev-server] Trying to reconnect...",
23 | "WebSocket connection to 'ws://127.0.0.1:8163/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED",
24 | "[webpack-dev-server] JSHandle@object",
25 | "[webpack-dev-server] Trying to reconnect...",
26 | "WebSocket connection to 'ws://127.0.0.1:8163/ws' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED",
27 | "[webpack-dev-server] JSHandle@object",
28 | ]
29 | `;
30 |
31 | exports[`client.reconnect option specified as number should try to reconnect 2 times: page errors 1`] = `[]`;
32 |
33 | exports[`client.reconnect option specified as number should try to reconnect 2 times: response status 1`] = `200`;
34 |
35 | exports[`client.reconnect option specified as true should try to reconnect unlimited times: page errors 1`] = `[]`;
36 |
37 | exports[`client.reconnect option specified as true should try to reconnect unlimited times: response status 1`] = `200`;
38 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/client.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`client option configure client entry should disable client entry: console messages 1`] = `[]`;
4 |
5 | exports[`client option configure client entry should disable client entry: page errors 1`] = `[]`;
6 |
7 | exports[`client option configure client entry should disable client entry: response status 1`] = `200`;
8 |
9 | exports[`client option configure client entry should redirect client entry to rspack: console messages 1`] = `[]`;
10 |
11 | exports[`client option configure client entry should redirect client entry to rspack: page errors 1`] = `[]`;
12 |
13 | exports[`client option configure client entry should redirect client entry to rspack: response status 1`] = `200`;
14 |
15 | exports[`client option default behaviour responds with a 200 status code for /ws path: console messages 1`] = `[]`;
16 |
17 | exports[`client option default behaviour responds with a 200 status code for /ws path: page errors 1`] = `[]`;
18 |
19 | exports[`client option default behaviour responds with a 200 status code for /ws path: response status 1`] = `200`;
20 |
21 | exports[`client option override client entry should disable client entry: response status 1`] = `200`;
22 |
23 | exports[`client option should respect path option responds with a 200 status code for /foo/test/bar path: console messages 1`] = `[]`;
24 |
25 | exports[`client option should respect path option responds with a 200 status code for /foo/test/bar path: page errors 1`] = `[]`;
26 |
27 | exports[`client option should respect path option responds with a 200 status code for /foo/test/bar path: response status 1`] = `200`;
28 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/compress.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`compress option as false should handle GET request to bundle file: console messages 1`] = `[]`;
4 |
5 | exports[`compress option as false should handle GET request to bundle file: page errors 1`] = `[]`;
6 |
7 | exports[`compress option as false should handle GET request to bundle file: response headers content-encoding 1`] = `undefined`;
8 |
9 | exports[`compress option as false should handle GET request to bundle file: response status 1`] = `200`;
10 |
11 | exports[`compress option as true should handle GET request to bundle file: console messages 1`] = `[]`;
12 |
13 | exports[`compress option as true should handle GET request to bundle file: page errors 1`] = `[]`;
14 |
15 | exports[`compress option as true should handle GET request to bundle file: response headers content-encoding 1`] = `"gzip"`;
16 |
17 | exports[`compress option as true should handle GET request to bundle file: response status 1`] = `200`;
18 |
19 | exports[`compress option enabled by default when not specified should handle GET request to bundle file: console messages 1`] = `[]`;
20 |
21 | exports[`compress option enabled by default when not specified should handle GET request to bundle file: page errors 1`] = `[]`;
22 |
23 | exports[`compress option enabled by default when not specified should handle GET request to bundle file: response headers content-encoding 1`] = `"gzip"`;
24 |
25 | exports[`compress option enabled by default when not specified should handle GET request to bundle file: response status 1`] = `200`;
26 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/entry.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`entry should work with dynamic async entry: console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`entry should work with dynamic async entry: page errors 1`] = `[]`;
12 |
13 | exports[`entry should work with dynamic entry: console messages 1`] = `
14 | [
15 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
16 | "[HMR] Waiting for update signal from WDS...",
17 | "Hey.",
18 | ]
19 | `;
20 |
21 | exports[`entry should work with dynamic entry: page errors 1`] = `[]`;
22 |
23 | exports[`entry should work with empty: console messages 1`] = `
24 | [
25 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
26 | "[HMR] Waiting for update signal from WDS...",
27 | "Hey.",
28 | ]
29 | `;
30 |
31 | exports[`entry should work with empty: page errors 1`] = `[]`;
32 |
33 | exports[`entry should work with multiple entries #2: console messages 1`] = `
34 | [
35 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
36 | "[HMR] Waiting for update signal from WDS...",
37 | "Bar.",
38 | ]
39 | `;
40 |
41 | exports[`entry should work with multiple entries #2: page errors 1`] = `[]`;
42 |
43 | exports[`entry should work with multiple entries and "dependOn": console messages 1`] = `
44 | [
45 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
46 | "[HMR] Waiting for update signal from WDS...",
47 | "Bar.",
48 | "Hey.",
49 | ]
50 | `;
51 |
52 | exports[`entry should work with multiple entries and "dependOn": page errors 1`] = `[]`;
53 |
54 | exports[`entry should work with multiple entries: console messages 1`] = `
55 | [
56 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
57 | "[HMR] Waiting for update signal from WDS...",
58 | "Hey.",
59 | ]
60 | `;
61 |
62 | exports[`entry should work with multiple entries: page errors 1`] = `[]`;
63 |
64 | exports[`entry should work with object entry: console messages 1`] = `
65 | [
66 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
67 | "[HMR] Waiting for update signal from WDS...",
68 | "Hey.",
69 | ]
70 | `;
71 |
72 | exports[`entry should work with object entry: page errors 1`] = `[]`;
73 |
74 | exports[`entry should work with single array entry: console messages 1`] = `
75 | [
76 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
77 | "[HMR] Waiting for update signal from WDS...",
78 | "Hey.",
79 | "Bar.",
80 | ]
81 | `;
82 |
83 | exports[`entry should work with single array entry: page errors 1`] = `[]`;
84 |
85 | exports[`entry should work with single entry: console messages 1`] = `
86 | [
87 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
88 | "[HMR] Waiting for update signal from WDS...",
89 | "Hey.",
90 | ]
91 | `;
92 |
93 | exports[`entry should work with single entry: page errors 1`] = `[]`;
94 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/headers.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`headers option as a function returning an array should handle GET request with headers: console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`headers option as a function returning an array should handle GET request with headers: page errors 1`] = `[]`;
12 |
13 | exports[`headers option as a function returning an array should handle GET request with headers: response headers x-bar 1`] = `"value2"`;
14 |
15 | exports[`headers option as a function returning an array should handle GET request with headers: response headers x-foo 1`] = `"value1"`;
16 |
17 | exports[`headers option as a function returning an array should handle GET request with headers: response status 1`] = `200`;
18 |
19 | exports[`headers option as a function should handle GET request with headers as a function: console messages 1`] = `
20 | [
21 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
22 | "[HMR] Waiting for update signal from WDS...",
23 | "Hey.",
24 | ]
25 | `;
26 |
27 | exports[`headers option as a function should handle GET request with headers as a function: page errors 1`] = `[]`;
28 |
29 | exports[`headers option as a function should handle GET request with headers as a function: response headers x-bar 1`] = `
30 | "key1=value1
31 | key2=value2"
32 | `;
33 |
34 | exports[`headers option as a function should handle GET request with headers as a function: response status 1`] = `200`;
35 |
36 | exports[`headers option as a string and support HEAD request should handle HEAD request with headers: console messages 1`] = `
37 | [
38 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
39 | "[HMR] Waiting for update signal from WDS...",
40 | "Hey.",
41 | ]
42 | `;
43 |
44 | exports[`headers option as a string and support HEAD request should handle HEAD request with headers: page errors 1`] = `[]`;
45 |
46 | exports[`headers option as a string and support HEAD request should handle HEAD request with headers: response headers x-foo 1`] = `"dev-server headers"`;
47 |
48 | exports[`headers option as a string and support HEAD request should handle HEAD request with headers: response status 1`] = `200`;
49 |
50 | exports[`headers option as a string should handle GET request with headers: console messages 1`] = `
51 | [
52 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
53 | "[HMR] Waiting for update signal from WDS...",
54 | "Hey.",
55 | ]
56 | `;
57 |
58 | exports[`headers option as a string should handle GET request with headers: page errors 1`] = `[]`;
59 |
60 | exports[`headers option as a string should handle GET request with headers: response headers x-foo 1`] = `"dev-server headers"`;
61 |
62 | exports[`headers option as a string should handle GET request with headers: response status 1`] = `200`;
63 |
64 | exports[`headers option as an array of objects should handle GET request with headers: console messages 1`] = `
65 | [
66 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
67 | "[HMR] Waiting for update signal from WDS...",
68 | "Hey.",
69 | ]
70 | `;
71 |
72 | exports[`headers option as an array of objects should handle GET request with headers: page errors 1`] = `[]`;
73 |
74 | exports[`headers option as an array of objects should handle GET request with headers: response headers x-bar 1`] = `"value2"`;
75 |
76 | exports[`headers option as an array of objects should handle GET request with headers: response headers x-foo 1`] = `"value1"`;
77 |
78 | exports[`headers option as an array of objects should handle GET request with headers: response status 1`] = `200`;
79 |
80 | exports[`headers option as an array should handle GET request with headers as an array: console messages 1`] = `
81 | [
82 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
83 | "[HMR] Waiting for update signal from WDS...",
84 | "Hey.",
85 | ]
86 | `;
87 |
88 | exports[`headers option as an array should handle GET request with headers as an array: page errors 1`] = `[]`;
89 |
90 | exports[`headers option as an array should handle GET request with headers as an array: response headers x-bar 1`] = `
91 | "key1=value1
92 | key2=value2"
93 | `;
94 |
95 | exports[`headers option as an array should handle GET request with headers as an array: response status 1`] = `200`;
96 |
97 | exports[`headers option dev middleware headers take precedence for dev middleware output files should handle GET request with headers as a function: console messages 1`] = `
98 | [
99 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
100 | "[HMR] Waiting for update signal from WDS...",
101 | "Hey.",
102 | ]
103 | `;
104 |
105 | exports[`headers option dev middleware headers take precedence for dev middleware output files should handle GET request with headers as a function: page errors 1`] = `[]`;
106 |
107 | exports[`headers option dev middleware headers take precedence for dev middleware output files should handle GET request with headers as a function: response headers x-foo 1`] = `"dev-middleware-headers"`;
108 |
109 | exports[`headers option dev middleware headers take precedence for dev middleware output files should handle GET request with headers as a function: response status 1`] = `200`;
110 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/host.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`host should work using "127.0.0.1" host and "auto" port: console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`host should work using "127.0.0.1" host and "auto" port: page errors 1`] = `[]`;
12 |
13 | exports[`host should work using "127.0.0.1" host and port as number: console messages 1`] = `
14 | [
15 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
16 | "[HMR] Waiting for update signal from WDS...",
17 | "Hey.",
18 | ]
19 | `;
20 |
21 | exports[`host should work using "127.0.0.1" host and port as number: page errors 1`] = `[]`;
22 |
23 | exports[`host should work using "127.0.0.1" host and port as string: console messages 1`] = `
24 | [
25 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
26 | "[HMR] Waiting for update signal from WDS...",
27 | "Hey.",
28 | ]
29 | `;
30 |
31 | exports[`host should work using "127.0.0.1" host and port as string: page errors 1`] = `[]`;
32 |
33 | exports[`host should work using "localhost" host and "auto" port: console messages 1`] = `
34 | [
35 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
36 | "[HMR] Waiting for update signal from WDS...",
37 | "Hey.",
38 | ]
39 | `;
40 |
41 | exports[`host should work using "localhost" host and "auto" port: page errors 1`] = `[]`;
42 |
43 | exports[`host should work using "localhost" host and port as number: console messages 1`] = `
44 | [
45 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
46 | "[HMR] Waiting for update signal from WDS...",
47 | "Hey.",
48 | ]
49 | `;
50 |
51 | exports[`host should work using "localhost" host and port as number: page errors 1`] = `[]`;
52 |
53 | exports[`host should work using "localhost" host and port as string: console messages 1`] = `
54 | [
55 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
56 | "[HMR] Waiting for update signal from WDS...",
57 | "Hey.",
58 | ]
59 | `;
60 |
61 | exports[`host should work using "localhost" host and port as string: page errors 1`] = `[]`;
62 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/ipc.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`web socket server URL should work with the "ipc" option using "string" value ("sockjs"): console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`web socket server URL should work with the "ipc" option using "string" value ("sockjs"): page errors 1`] = `[]`;
12 |
13 | exports[`web socket server URL should work with the "ipc" option using "string" value ("ws"): console messages 1`] = `
14 | [
15 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
16 | "[HMR] Waiting for update signal from WDS...",
17 | "Hey.",
18 | ]
19 | `;
20 |
21 | exports[`web socket server URL should work with the "ipc" option using "string" value ("ws"): page errors 1`] = `[]`;
22 |
23 | exports[`web socket server URL should work with the "ipc" option using "true" value ("sockjs"): console messages 1`] = `
24 | [
25 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
26 | "[HMR] Waiting for update signal from WDS...",
27 | "Hey.",
28 | ]
29 | `;
30 |
31 | exports[`web socket server URL should work with the "ipc" option using "true" value ("sockjs"): page errors 1`] = `[]`;
32 |
33 | exports[`web socket server URL should work with the "ipc" option using "true" value ("ws"): console messages 1`] = `
34 | [
35 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
36 | "[HMR] Waiting for update signal from WDS...",
37 | "Hey.",
38 | ]
39 | `;
40 |
41 | exports[`web socket server URL should work with the "ipc" option using "true" value ("ws"): page errors 1`] = `[]`;
42 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/mime-types.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`mimeTypes option as an object with a custom type should request file with different js mime type: console messages 1`] = `[]`;
4 |
5 | exports[`mimeTypes option as an object with a custom type should request file with different js mime type: page errors 1`] = `[]`;
6 |
7 | exports[`mimeTypes option as an object with a custom type should request file with different js mime type: response headers content-type 1`] = `"text/html; charset=utf-8"`;
8 |
9 | exports[`mimeTypes option as an object with a custom type should request file with different js mime type: response status 1`] = `200`;
10 |
11 | exports[`mimeTypes option as an object with a remapped type should request file with different js mime type: console messages 1`] = `[]`;
12 |
13 | exports[`mimeTypes option as an object with a remapped type should request file with different js mime type: page errors 1`] = `[]`;
14 |
15 | exports[`mimeTypes option as an object with a remapped type should request file with different js mime type: response headers content-type 1`] = `"text/plain; charset=utf-8"`;
16 |
17 | exports[`mimeTypes option as an object with a remapped type should request file with different js mime type: response status 1`] = `200`;
18 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/module-federation.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Module federation should use plugin should contain hot script in main.js: console messages 1`] = `[]`;
4 |
5 | exports[`Module federation should use plugin should contain hot script in main.js: page errors 1`] = `[]`;
6 |
7 | exports[`Module federation should use plugin should contain hot script in remoteEntry.js: console messages 1`] = `[]`;
8 |
9 | exports[`Module federation should use plugin should contain hot script in remoteEntry.js: page errors 1`] = `[]`;
10 |
11 | exports[`Module federation should work with multi compiler config should use the last entry export: console messages 1`] = `[]`;
12 |
13 | exports[`Module federation should work with multi compiler config should use the last entry export: page errors 1`] = `[]`;
14 |
15 | exports[`Module federation should work with object multi-entry config should support the named entry export: console messages 1`] = `[]`;
16 |
17 | exports[`Module federation should work with object multi-entry config should support the named entry export: page errors 1`] = `[]`;
18 |
19 | exports[`Module federation should work with object multi-entry config should use the last entry export: console messages 1`] = `[]`;
20 |
21 | exports[`Module federation should work with object multi-entry config should use the last entry export: page errors 1`] = `[]`;
22 |
23 | exports[`Module federation should work with simple multi-entry config should use the last entry export: console messages 1`] = `[]`;
24 |
25 | exports[`Module federation should work with simple multi-entry config should use the last entry export: page errors 1`] = `[]`;
26 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/on-listening.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`onListening option should handle GET request to /listening/some/path route: console messages 1`] = `[]`;
4 |
5 | exports[`onListening option should handle GET request to /listening/some/path route: page errors 1`] = `[]`;
6 |
7 | exports[`onListening option should handle GET request to /listening/some/path route: response headers content-type 1`] = `"text/html; charset=utf-8"`;
8 |
9 | exports[`onListening option should handle GET request to /listening/some/path route: response status 1`] = `200`;
10 |
11 | exports[`onListening option should handle GET request to /listening/some/path route: response text 1`] = `"listening"`;
12 |
13 | exports[`onListening option should handle POST request to /listening/some/path route: console messages 1`] = `[]`;
14 |
15 | exports[`onListening option should handle POST request to /listening/some/path route: page errors 1`] = `[]`;
16 |
17 | exports[`onListening option should handle POST request to /listening/some/path route: response headers content-type 1`] = `"text/html; charset=utf-8"`;
18 |
19 | exports[`onListening option should handle POST request to /listening/some/path route: response status 1`] = `200`;
20 |
21 | exports[`onListening option should handle POST request to /listening/some/path route: response text 1`] = `"listening POST"`;
22 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/port.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`port should work using "" port : console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`port should work using "" port : page errors 1`] = `[]`;
12 |
13 | exports[`port should work using "0" port : console messages 1`] = `
14 | [
15 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
16 | "[HMR] Waiting for update signal from WDS...",
17 | "Hey.",
18 | ]
19 | `;
20 |
21 | exports[`port should work using "0" port : page errors 1`] = `[]`;
22 |
23 | exports[`port should work using "8161" port : console messages 1`] = `
24 | [
25 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
26 | "[HMR] Waiting for update signal from WDS...",
27 | "Hey.",
28 | ]
29 | `;
30 |
31 | exports[`port should work using "8161" port : console messages 2`] = `
32 | [
33 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
34 | "[HMR] Waiting for update signal from WDS...",
35 | "Hey.",
36 | ]
37 | `;
38 |
39 | exports[`port should work using "8161" port : page errors 1`] = `[]`;
40 |
41 | exports[`port should work using "8161" port : page errors 2`] = `[]`;
42 |
43 | exports[`port should work using "auto" port : console messages 1`] = `
44 | [
45 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
46 | "[HMR] Waiting for update signal from WDS...",
47 | "Hey.",
48 | ]
49 | `;
50 |
51 | exports[`port should work using "auto" port : page errors 1`] = `[]`;
52 |
53 | exports[`port should work using "undefined" port : console messages 1`] = `
54 | [
55 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
56 | "[HMR] Waiting for update signal from WDS...",
57 | "Hey.",
58 | ]
59 | `;
60 |
61 | exports[`port should work using "undefined" port : page errors 1`] = `[]`;
62 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/server-and-client-transport.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`server and client transport should throw an error on invalid path to client transport 1`] = `"client.webSocketTransport must be a string denoting a default implementation (e.g. 'sockjs', 'ws') or a full path to a JS file via require.resolve(...) which exports a class "`;
4 |
5 | exports[`server and client transport should throw an error on invalid path to server transport 1`] = `"webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) via require.resolve(...), or the class itself which extends BaseServer"`;
6 |
7 | exports[`server and client transport should throw an error on wrong path 1`] = `"webSocketServer (webSocketServer.type) must be a string denoting a default implementation (e.g. 'ws', 'sockjs'), a full path to a JS file which exports a class extending BaseServer (webpack-dev-server/lib/servers/BaseServer.js) via require.resolve(...), or the class itself which extends BaseServer"`;
8 |
9 | exports[`server and client transport should use "sockjs" transport and "sockjs" web socket server 1`] = `
10 | [
11 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
12 | "[HMR] Waiting for update signal from WDS...",
13 | ]
14 | `;
15 |
16 | exports[`server and client transport should use "sockjs" transport, when web socket server is not specify 1`] = `[]`;
17 |
18 | exports[`server and client transport should use "sockjs" web socket server when specify "sockjs" value 1`] = `
19 | [
20 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
21 | "[HMR] Waiting for update signal from WDS...",
22 | ]
23 | `;
24 |
25 | exports[`server and client transport should use "sockjs" web socket server when specify "sockjs" value using object 1`] = `
26 | [
27 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
28 | "[HMR] Waiting for update signal from WDS...",
29 | ]
30 | `;
31 |
32 | exports[`server and client transport should use "ws" transport and "ws" web socket server 1`] = `
33 | [
34 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
35 | "[HMR] Waiting for update signal from WDS...",
36 | ]
37 | `;
38 |
39 | exports[`server and client transport should use "ws" transport, when web socket server is not specify 1`] = `
40 | [
41 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
42 | "[HMR] Waiting for update signal from WDS...",
43 | ]
44 | `;
45 |
46 | exports[`server and client transport should use "ws" web socket server when specify "ws" value 1`] = `
47 | [
48 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
49 | "[HMR] Waiting for update signal from WDS...",
50 | ]
51 | `;
52 |
53 | exports[`server and client transport should use "ws" web socket server when specify "ws" value using object 1`] = `
54 | [
55 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
56 | "[HMR] Waiting for update signal from WDS...",
57 | ]
58 | `;
59 |
60 | exports[`server and client transport should use custom transport and "sockjs" web socket server 1`] = `
61 | [
62 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
63 | "[HMR] Waiting for update signal from WDS...",
64 | "open",
65 | "hot",
66 | "liveReload",
67 | "reconnect",
68 | "overlay",
69 | "hash",
70 | "ok",
71 | ]
72 | `;
73 |
74 | exports[`server and client transport should use custom web socket server when specify class 1`] = `
75 | [
76 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
77 | "[HMR] Waiting for update signal from WDS...",
78 | ]
79 | `;
80 |
81 | exports[`server and client transport should use custom web socket server when specify class using object 1`] = `
82 | [
83 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
84 | "[HMR] Waiting for update signal from WDS...",
85 | ]
86 | `;
87 |
88 | exports[`server and client transport should use custom web socket server when specify path to class 1`] = `
89 | [
90 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
91 | "[HMR] Waiting for update signal from WDS...",
92 | ]
93 | `;
94 |
95 | exports[`server and client transport should use custom web socket server when specify path to class using object 1`] = `
96 | [
97 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
98 | "[HMR] Waiting for update signal from WDS...",
99 | ]
100 | `;
101 |
102 | exports[`server and client transport should use default web socket server ("ws") 1`] = `
103 | [
104 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
105 | "[HMR] Waiting for update signal from WDS...",
106 | ]
107 | `;
108 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/setup-exit-signals.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGINT: console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGINT: page errors 1`] = `[]`;
12 |
13 | exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGINT: response status 1`] = `200`;
14 |
15 | exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGTERM: console messages 1`] = `
16 | [
17 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
18 | "[HMR] Waiting for update signal from WDS...",
19 | "Hey.",
20 | ]
21 | `;
22 |
23 | exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGTERM: page errors 1`] = `[]`;
24 |
25 | exports[`setupExitSignals option should handle 'SIGINT' and 'SIGTERM' signals should close and exit on SIGTERM: response status 1`] = `200`;
26 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/setup-middlewares.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: console messages 1`] = `[]`;
4 |
5 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: page errors 1`] = `[]`;
6 |
7 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 1`] = `"text/html; charset=utf-8"`;
8 |
9 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 2`] = `"text/html; charset=utf-8"`;
10 |
11 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 3`] = `"text/html; charset=utf-8"`;
12 |
13 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response headers content-type 4`] = `"text/html; charset=utf-8"`;
14 |
15 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 1`] = `200`;
16 |
17 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 2`] = `200`;
18 |
19 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 3`] = `200`;
20 |
21 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response status 4`] = `200`;
22 |
23 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 1`] = `"setup-middlewares option GET"`;
24 |
25 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 2`] = `"Hello World with path!"`;
26 |
27 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 3`] = `"Hello World without path!"`;
28 |
29 | exports[`setupMiddlewares option should handle GET request to /setup-middleware/some/path route: response text 4`] = `"Hello World as function!"`;
30 |
31 | exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: console messages 1`] = `[]`;
32 |
33 | exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: page errors 1`] = `[]`;
34 |
35 | exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: response headers content-type 1`] = `"text/html; charset=utf-8"`;
36 |
37 | exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: response status 1`] = `200`;
38 |
39 | exports[`setupMiddlewares option should handle POST request to /setup-middleware/some/path route: response text 1`] = `"setup-middlewares option POST"`;
40 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/stats.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`stats should work and respect the "ignoreWarnings" option 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | ]
9 | `;
10 |
11 | exports[`stats should work using "{ assets: false }" value for the "stats" option 1`] = `
12 | [
13 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
14 | "[HMR] Waiting for update signal from WDS...",
15 | "Hey.",
16 | ]
17 | `;
18 |
19 | exports[`stats should work using "{}" value for the "stats" option 1`] = `
20 | [
21 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
22 | "[HMR] Waiting for update signal from WDS...",
23 | "Hey.",
24 | ]
25 | `;
26 |
27 | exports[`stats should work using "errors-only" value for the "stats" option 1`] = `
28 | [
29 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
30 | "[HMR] Waiting for update signal from WDS...",
31 | "Hey.",
32 | ]
33 | `;
34 |
35 | exports[`stats should work using "false" value for the "stats" option 1`] = `
36 | [
37 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
38 | "[HMR] Waiting for update signal from WDS...",
39 | "Hey.",
40 | ]
41 | `;
42 |
43 | exports[`stats should work using "undefined" value for the "stats" option 1`] = `
44 | [
45 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
46 | "[HMR] Waiting for update signal from WDS...",
47 | "Hey.",
48 | ]
49 | `;
50 |
51 | exports[`stats should work when "stats" is not specified 1`] = `
52 | [
53 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
54 | "[HMR] Waiting for update signal from WDS...",
55 | "Hey.",
56 | ]
57 | `;
58 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/target.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`target should work using "async-node" target: console messages 1`] = `
4 | [
5 | "[HMR] Waiting for update signal from WDS...",
6 | "Hey.",
7 | ]
8 | `;
9 |
10 | exports[`target should work using "browserslist:defaults" target: console messages 1`] = `
11 | [
12 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
13 | "[HMR] Waiting for update signal from WDS...",
14 | "Hey.",
15 | ]
16 | `;
17 |
18 | exports[`target should work using "electron-main" target: console messages 1`] = `
19 | [
20 | "[HMR] Waiting for update signal from WDS...",
21 | "Hey.",
22 | ]
23 | `;
24 |
25 | exports[`target should work using "electron-preload" target: console messages 1`] = `
26 | [
27 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
28 | "[HMR] Waiting for update signal from WDS...",
29 | "Hey.",
30 | ]
31 | `;
32 |
33 | exports[`target should work using "electron-renderer" target: console messages 1`] = `[]`;
34 |
35 | exports[`target should work using "es5" target: console messages 1`] = `
36 | [
37 | "[HMR] Waiting for update signal from WDS...",
38 | "Hey.",
39 | ]
40 | `;
41 |
42 | exports[`target should work using "false" target: console messages 1`] = `
43 | [
44 | "[HMR] Waiting for update signal from WDS...",
45 | "Hey.",
46 | ]
47 | `;
48 |
49 | exports[`target should work using "node" target: console messages 1`] = `
50 | [
51 | "[HMR] Waiting for update signal from WDS...",
52 | "Hey.",
53 | ]
54 | `;
55 |
56 | exports[`target should work using "node-webkit" target: console messages 1`] = `
57 | [
58 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
59 | "[HMR] Waiting for update signal from WDS...",
60 | "Hey.",
61 | ]
62 | `;
63 |
64 | exports[`target should work using "nwjs" target: console messages 1`] = `
65 | [
66 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
67 | "[HMR] Waiting for update signal from WDS...",
68 | "Hey.",
69 | ]
70 | `;
71 |
72 | exports[`target should work using "web" target: console messages 1`] = `
73 | [
74 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
75 | "[HMR] Waiting for update signal from WDS...",
76 | "Hey.",
77 | ]
78 | `;
79 |
80 | exports[`target should work using "web,es5" target: console messages 1`] = `
81 | [
82 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
83 | "[HMR] Waiting for update signal from WDS...",
84 | "Hey.",
85 | ]
86 | `;
87 |
88 | exports[`target should work using "webworker" target: console messages 1`] = `
89 | [
90 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
91 | "[HMR] Waiting for update signal from WDS...",
92 | "Hey.",
93 | ]
94 | `;
95 |
96 | exports[`target should work using multi compiler mode with \`web\` and \`webworker\` targets with \`devServer: false\`: console messages 1`] = `
97 | [
98 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
99 | "[HMR] Waiting for update signal from WDS...",
100 | "Worker said: I'm working before postMessage",
101 | "Worker said: Message sent: message",
102 | ]
103 | `;
104 |
105 | exports[`target should work using multi compiler mode with \`web\` and \`webworker\` targets with \`devServer: false\`: page errors 1`] = `[]`;
106 |
107 | exports[`target should work using multi compiler mode with \`web\` and \`webworker\` targets: console messages 1`] = `
108 | [
109 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
110 | "[HMR] Waiting for update signal from WDS...",
111 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
112 | "[HMR] Waiting for update signal from WDS...",
113 | "Worker said: I'm working before postMessage",
114 | "Worker said: Message sent: message",
115 | ]
116 | `;
117 |
118 | exports[`target should work using multi compiler mode with \`web\` and \`webworker\` targets: page errors 1`] = `[]`;
119 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/web-socket-communication.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`web socket communication should work and close web socket client connection when web socket server closed ("sockjs"): console messages 1`] = `
4 | [
5 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
6 | "[HMR] Waiting for update signal from WDS...",
7 | "Hey.",
8 | "[webpack-dev-server] Disconnected!",
9 | "[webpack-dev-server] Trying to reconnect...",
10 | ]
11 | `;
12 |
13 | exports[`web socket communication should work and close web socket client connection when web socket server closed ("sockjs"): page errors 1`] = `[]`;
14 |
15 | exports[`web socket communication should work and close web socket client connection when web socket server closed ("ws"): console messages 1`] = `
16 | [
17 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
18 | "[HMR] Waiting for update signal from WDS...",
19 | "Hey.",
20 | "[webpack-dev-server] Disconnected!",
21 | "[webpack-dev-server] Trying to reconnect...",
22 | ]
23 | `;
24 |
25 | exports[`web socket communication should work and close web socket client connection when web socket server closed ("ws"): page errors 1`] = `[]`;
26 |
27 | exports[`web socket communication should work and reconnect when the connection is lost ("sockjs"): console messages 1`] = `
28 | [
29 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
30 | "[HMR] Waiting for update signal from WDS...",
31 | "Hey.",
32 | "[webpack-dev-server] Disconnected!",
33 | "[webpack-dev-server] Trying to reconnect...",
34 | "[webpack-dev-server] App hot update...",
35 | "[HMR] Checking for updates on the server...",
36 | "Failed to load resource: the server responded with a status of 404 (Not Found)",
37 | "[HMR] Cannot find update. Need to do a full reload!",
38 | "[HMR] (Probably because of restarting the webpack-dev-server)",
39 | "Failed to load resource: the server responded with a status of 404 (Not Found)",
40 | ]
41 | `;
42 |
43 | exports[`web socket communication should work and reconnect when the connection is lost ("sockjs"): page errors 1`] = `[]`;
44 |
45 | exports[`web socket communication should work and reconnect when the connection is lost ("ws"): console messages 1`] = `
46 | [
47 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
48 | "[HMR] Waiting for update signal from WDS...",
49 | "Hey.",
50 | "[webpack-dev-server] Disconnected!",
51 | "[webpack-dev-server] Trying to reconnect...",
52 | "[webpack-dev-server] App hot update...",
53 | "[HMR] Checking for updates on the server...",
54 | "Failed to load resource: the server responded with a status of 404 (Not Found)",
55 | "[HMR] Cannot find update. Need to do a full reload!",
56 | "[HMR] (Probably because of restarting the webpack-dev-server)",
57 | "Failed to load resource: the server responded with a status of 404 (Not Found)",
58 | ]
59 | `;
60 |
61 | exports[`web socket communication should work and reconnect when the connection is lost ("ws"): page errors 1`] = `[]`;
62 |
63 | exports[`web socket communication should work and terminate client that is not alive ("sockjs"): console messages 1`] = `
64 | [
65 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
66 | "[HMR] Waiting for update signal from WDS...",
67 | "Hey.",
68 | ]
69 | `;
70 |
71 | exports[`web socket communication should work and terminate client that is not alive ("sockjs"): page errors 1`] = `[]`;
72 |
73 | exports[`web socket communication should work and terminate client that is not alive ("ws"): console messages 1`] = `
74 | [
75 | "[webpack-dev-server] Server started: Hot Module Replacement enabled, Live Reloading enabled, Progress disabled, Overlay enabled.",
76 | "[HMR] Waiting for update signal from WDS...",
77 | "Hey.",
78 | ]
79 | `;
80 |
81 | exports[`web socket communication should work and terminate client that is not alive ("ws"): page errors 1`] = `[]`;
82 |
--------------------------------------------------------------------------------
/tests/e2e/__snapshots__/web-socket-server.test.js.snap.webpack5:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`web socket server should work allow to disable: console messages 1`] = `
4 | [
5 | "Hey.",
6 | ]
7 | `;
8 |
9 | exports[`web socket server should work allow to disable: page errors 1`] = `[]`;
10 |
--------------------------------------------------------------------------------
/tests/e2e/app.test.js:
--------------------------------------------------------------------------------
1 | const fs = require("node:fs");
2 | const path = require("node:path");
3 | const webpack = require("@rspack/core");
4 | const wdm = require("webpack-dev-middleware");
5 | const { RspackDevServer: Server } = require("@rspack/dev-server");
6 | const config = require("../fixtures/client-config/webpack.config");
7 | const runBrowser = require("../helpers/run-browser");
8 | const port = require("../helpers/ports-map").app;
9 |
10 | const staticDirectory = path.resolve(
11 | __dirname,
12 | "../fixtures/static-config/public",
13 | );
14 |
15 | const apps = [
16 | ["express", () => require("express")(), "http"],
17 | ["express", () => require("express")(), "https"],
18 | ["express", () => require("express")(), "spdy"],
19 | ["connect", () => require("connect")(), "http"],
20 | ["connect", () => require("connect")(), "https"],
21 | ["connect", () => require("connect")(), "spdy"],
22 | ["connect", () => require("connect")(), "http2"],
23 | ["connect (async)", () => require("connect")(), "http"],
24 | [
25 | "hono",
26 | () => new (require("hono").Hono)(),
27 | (options, app) =>
28 | require("@hono/node-server").createAdaptorServer({
29 | fetch: app.fetch,
30 | }),
31 | (_, devServer) => [
32 | {
33 | name: "webpack-dev-middleware",
34 | middleware: wdm.honoWrapper(devServer.compiler),
35 | },
36 | ],
37 | ],
38 | [
39 | "hono",
40 | () => new (require("hono").Hono)(),
41 | (_, app) =>
42 | require("@hono/node-server").createAdaptorServer({
43 | fetch: app.fetch,
44 | createServer: require("node:https").createServer,
45 | serverOptions: {
46 | key: fs.readFileSync(
47 | path.resolve(__dirname, "../fixtures/ssl/localhost-privkey.pem"),
48 | ),
49 | cert: fs.readFileSync(
50 | path.resolve(__dirname, "../fixtures/ssl/localhost-cert.pem"),
51 | ),
52 | },
53 | }),
54 | (_, devServer) => [
55 | {
56 | name: "webpack-dev-middleware",
57 | middleware: wdm.honoWrapper(devServer.compiler),
58 | },
59 | ],
60 | ],
61 | [
62 | "hono",
63 | () => new (require("hono").Hono)(),
64 | {
65 | type: (options, app) =>
66 | require("@hono/node-server").createAdaptorServer({
67 | fetch: app.fetch,
68 | createServer: require("node:http2").createSecureServer,
69 | serverOptions: options,
70 | }),
71 | options: {
72 | allowHTTP1: true,
73 | key: fs.readFileSync(
74 | path.resolve(__dirname, "../fixtures/ssl/localhost-privkey.pem"),
75 | ),
76 | cert: fs.readFileSync(
77 | path.resolve(__dirname, "../fixtures/ssl/localhost-cert.pem"),
78 | ),
79 | },
80 | },
81 | (_, devServer) => [
82 | {
83 | name: "webpack-dev-middleware",
84 | middleware: wdm.honoWrapper(devServer.compiler),
85 | },
86 | ],
87 | ],
88 | ];
89 |
90 | describe("app option", () => {
91 | for (const [appName, app, server, setupMiddlewares] of apps) {
92 | let compiler;
93 | let devServer;
94 | let page;
95 | let browser;
96 | let pageErrors;
97 | let consoleMessages;
98 |
99 | describe(`should work using "${appName}" application and "${typeof server === "function" ? "custom server" : server}" server`, () => {
100 | beforeEach(async () => {
101 | compiler = webpack(config);
102 |
103 | devServer = new Server(
104 | {
105 | static: {
106 | directory: staticDirectory,
107 | watch: false,
108 | },
109 | app,
110 | server,
111 | port,
112 | setupMiddlewares:
113 | typeof setupMiddlewares !== "undefined"
114 | ? setupMiddlewares
115 | : // eslint-disable-next-line no-undefined
116 | undefined,
117 | },
118 | compiler,
119 | );
120 |
121 | await devServer.start();
122 |
123 | ({ page, browser } = await runBrowser());
124 |
125 | pageErrors = [];
126 | consoleMessages = [];
127 | });
128 |
129 | afterEach(async () => {
130 | await browser.close();
131 | await devServer.stop();
132 | await new Promise((resolve) => {
133 | compiler.close(() => {
134 | resolve();
135 | });
136 | });
137 | });
138 |
139 | it("should handle GET request to index route (/)", async () => {
140 | page
141 | .on("console", (message) => {
142 | consoleMessages.push(message);
143 | })
144 | .on("pageerror", (error) => {
145 | pageErrors.push(error);
146 | });
147 |
148 | const pageUrl = devServer.isTlsServer
149 | ? `https://127.0.0.1:${port}/`
150 | : `http://127.0.0.1:${port}/`;
151 |
152 | const response = await page.goto(pageUrl, {
153 | waitUntil: "networkidle0",
154 | });
155 |
156 | const HTTPVersion = await page.evaluate(
157 | () => performance.getEntries()[0].nextHopProtocol,
158 | );
159 |
160 | if (
161 | server === "spdy" ||
162 | server === "http2" ||
163 | server.options?.allowHTTP1
164 | ) {
165 | expect(HTTPVersion).toEqual("h2");
166 | } else {
167 | expect(HTTPVersion).toEqual("http/1.1");
168 | }
169 |
170 | expect(response.status()).toMatchSnapshot("response status");
171 | expect(await response.text()).toMatchSnapshot("response text");
172 | expect(
173 | consoleMessages.map((message) => message.text()),
174 | ).toMatchSnapshot("console messages");
175 | expect(pageErrors).toMatchSnapshot("page errors");
176 | });
177 | });
178 | }
179 | });
180 |
--------------------------------------------------------------------------------
/tests/e2e/client-reconnect.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/simple-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map")["client-reconnect-option"];
6 |
7 | describe("client.reconnect option", () => {
8 | describe("specified as true", () => {
9 | let compiler;
10 | let server;
11 | let page;
12 | let browser;
13 | let pageErrors;
14 | let consoleMessages;
15 |
16 | beforeEach(async () => {
17 | compiler = webpack(config);
18 |
19 | server = new Server({ port, client: { reconnect: true } }, compiler);
20 |
21 | await server.start();
22 |
23 | ({ page, browser } = await runBrowser());
24 |
25 | pageErrors = [];
26 | consoleMessages = [];
27 | });
28 |
29 | afterEach(async () => {
30 | await browser.close();
31 | });
32 |
33 | it("should try to reconnect unlimited times", async () => {
34 | page
35 | .on("console", (message) => {
36 | consoleMessages.push(message);
37 | })
38 | .on("pageerror", (error) => {
39 | pageErrors.push(error);
40 | });
41 |
42 | const response = await page.goto(`http://127.0.0.1:${port}/`, {
43 | waitUntil: "networkidle0",
44 | });
45 |
46 | try {
47 | expect(response.status()).toMatchSnapshot("response status");
48 | } finally {
49 | await server.stop();
50 | }
51 |
52 | let interval;
53 |
54 | await new Promise((resolve) => {
55 | interval = setInterval(() => {
56 | const retryingMessages = consoleMessages.filter((message) =>
57 | message.text().includes("Trying to reconnect..."),
58 | );
59 |
60 | if (retryingMessages.length >= 5) {
61 | clearInterval(interval);
62 |
63 | resolve();
64 | }
65 | }, 1000);
66 | });
67 |
68 | expect(pageErrors).toMatchSnapshot("page errors");
69 | });
70 | });
71 |
72 | describe("specified as false", () => {
73 | let compiler;
74 | let server;
75 | let page;
76 | let browser;
77 | let pageErrors;
78 | let consoleMessages;
79 |
80 | beforeEach(async () => {
81 | compiler = webpack(config);
82 |
83 | server = new Server({ port, client: { reconnect: false } }, compiler);
84 |
85 | await server.start();
86 |
87 | ({ page, browser } = await runBrowser());
88 |
89 | pageErrors = [];
90 | consoleMessages = [];
91 | });
92 |
93 | afterEach(async () => {
94 | await browser.close();
95 | });
96 |
97 | it("should not try to reconnect", async () => {
98 | page
99 | .on("console", (message) => {
100 | consoleMessages.push(message);
101 | })
102 | .on("pageerror", (error) => {
103 | pageErrors.push(error);
104 | });
105 |
106 | const response = await page.goto(`http://127.0.0.1:${port}/`, {
107 | waitUntil: "networkidle0",
108 | });
109 |
110 | try {
111 | expect(response.status()).toMatchSnapshot("response status");
112 | } finally {
113 | await server.stop();
114 | }
115 |
116 | // Can't wait to check for unlimited times so wait only for couple retries
117 | await new Promise((resolve) =>
118 | setTimeout(
119 | () => {
120 | resolve();
121 | },
122 | // eslint-disable-next-line no-restricted-properties
123 | 1000 * 2 ** 3,
124 | ),
125 | );
126 |
127 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
128 | "console messages",
129 | );
130 |
131 | expect(pageErrors).toMatchSnapshot("page errors");
132 | });
133 | });
134 |
135 | describe("specified as number", () => {
136 | let compiler;
137 | let server;
138 | let page;
139 | let browser;
140 | let pageErrors;
141 | let consoleMessages;
142 |
143 | beforeEach(async () => {
144 | compiler = webpack(config);
145 |
146 | server = new Server({ port, client: { reconnect: 2 } }, compiler);
147 |
148 | await server.start();
149 |
150 | ({ page, browser } = await runBrowser());
151 |
152 | pageErrors = [];
153 | consoleMessages = [];
154 | });
155 |
156 | afterEach(async () => {
157 | await browser.close();
158 | });
159 |
160 | it("should try to reconnect 2 times", async () => {
161 | page
162 | .on("console", (message) => {
163 | consoleMessages.push(message);
164 | })
165 | .on("pageerror", (error) => {
166 | pageErrors.push(error);
167 | });
168 |
169 | const response = await page.goto(`http://127.0.0.1:${port}/`, {
170 | waitUntil: "networkidle0",
171 | });
172 |
173 | try {
174 | expect(response.status()).toMatchSnapshot("response status");
175 | } finally {
176 | await server.stop();
177 | }
178 |
179 | // Can't wait to check for unlimited times so wait only for couple retries
180 | await new Promise((resolve) =>
181 | setTimeout(
182 | () => {
183 | resolve();
184 | },
185 | // eslint-disable-next-line no-restricted-properties
186 | 1000 * 2 ** 3,
187 | ),
188 | );
189 |
190 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
191 | "console messages",
192 | );
193 |
194 | expect(pageErrors).toMatchSnapshot("page errors");
195 | });
196 | });
197 | });
198 |
--------------------------------------------------------------------------------
/tests/e2e/compress.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/simple-config-other/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map")["compress-option"];
6 |
7 | describe("compress option", () => {
8 | describe("enabled by default when not specified", () => {
9 | let compiler;
10 | let server;
11 | let page;
12 | let browser;
13 | let pageErrors;
14 | let consoleMessages;
15 |
16 | beforeEach(async () => {
17 | compiler = webpack(config);
18 |
19 | server = new Server({ port }, compiler);
20 |
21 | await server.start();
22 |
23 | ({ page, browser } = await runBrowser());
24 |
25 | pageErrors = [];
26 | consoleMessages = [];
27 | });
28 |
29 | afterEach(async () => {
30 | await browser.close();
31 | await server.stop();
32 | });
33 |
34 | it("should handle GET request to bundle file", async () => {
35 | page
36 | .on("console", (message) => {
37 | consoleMessages.push(message);
38 | })
39 | .on("pageerror", (error) => {
40 | pageErrors.push(error);
41 | });
42 |
43 | const response = await page.goto(`http://127.0.0.1:${port}/main.js`, {
44 | waitUntil: "networkidle0",
45 | });
46 |
47 | expect(response.status()).toMatchSnapshot("response status");
48 |
49 | expect(response.headers()["content-encoding"]).toMatchSnapshot(
50 | "response headers content-encoding",
51 | );
52 |
53 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
54 | "console messages",
55 | );
56 |
57 | expect(pageErrors).toMatchSnapshot("page errors");
58 | });
59 | });
60 |
61 | describe("as true", () => {
62 | let compiler;
63 | let server;
64 | let page;
65 | let browser;
66 | let pageErrors;
67 | let consoleMessages;
68 |
69 | beforeEach(async () => {
70 | compiler = webpack(config);
71 |
72 | server = new Server(
73 | {
74 | compress: true,
75 | port,
76 | },
77 | compiler,
78 | );
79 |
80 | await server.start();
81 |
82 | ({ page, browser } = await runBrowser());
83 |
84 | pageErrors = [];
85 | consoleMessages = [];
86 | });
87 |
88 | afterEach(async () => {
89 | await browser.close();
90 | await server.stop();
91 | });
92 |
93 | it("should handle GET request to bundle file", async () => {
94 | page
95 | .on("console", (message) => {
96 | consoleMessages.push(message);
97 | })
98 | .on("pageerror", (error) => {
99 | pageErrors.push(error);
100 | });
101 |
102 | const response = await page.goto(`http://127.0.0.1:${port}/main.js`, {
103 | waitUntil: "networkidle0",
104 | });
105 |
106 | expect(response.status()).toMatchSnapshot("response status");
107 |
108 | expect(response.headers()["content-encoding"]).toMatchSnapshot(
109 | "response headers content-encoding",
110 | );
111 |
112 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
113 | "console messages",
114 | );
115 |
116 | expect(pageErrors).toMatchSnapshot("page errors");
117 | });
118 | });
119 |
120 | describe("as false", () => {
121 | let compiler;
122 | let server;
123 | let page;
124 | let browser;
125 | let pageErrors;
126 | let consoleMessages;
127 |
128 | beforeEach(async () => {
129 | compiler = webpack(config);
130 |
131 | server = new Server(
132 | {
133 | compress: false,
134 | port,
135 | },
136 | compiler,
137 | );
138 |
139 | await server.start();
140 |
141 | ({ page, browser } = await runBrowser());
142 |
143 | pageErrors = [];
144 | consoleMessages = [];
145 | });
146 |
147 | afterEach(async () => {
148 | await browser.close();
149 | await server.stop();
150 | });
151 |
152 | it("should handle GET request to bundle file", async () => {
153 | page
154 | .on("console", (message) => {
155 | consoleMessages.push(message);
156 | })
157 | .on("pageerror", (error) => {
158 | pageErrors.push(error);
159 | });
160 |
161 | const response = await page.goto(`http://127.0.0.1:${port}/main.js`, {
162 | waitUntil: "networkidle0",
163 | });
164 |
165 | expect(response.status()).toMatchSnapshot("response status");
166 |
167 | expect(response.headers()["content-encoding"]).toMatchSnapshot(
168 | "response headers content-encoding",
169 | );
170 |
171 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
172 | "console messages",
173 | );
174 |
175 | expect(pageErrors).toMatchSnapshot("page errors");
176 | });
177 | });
178 | });
179 |
--------------------------------------------------------------------------------
/tests/e2e/lazy-compilation.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const lazyCompilationSingleEntryConfig = require("../fixtures/lazy-compilation-single-entry/webpack.config");
4 | const lazyCompilationMultipleEntriesConfig = require("../fixtures/lazy-compilation-multiple-entries/webpack.config");
5 | const runBrowser = require("../helpers/run-browser");
6 | const port = require("../helpers/ports-map")["lazy-compilation"];
7 |
8 | describe("lazy compilation", () => {
9 | // TODO jest freeze due webpack do not close `eventsource`, we should uncomment this after fix it on webpack side
10 | it.skip("should work with single entry", async () => {
11 | const compiler = webpack(lazyCompilationSingleEntryConfig);
12 | const server = new Server({ port }, compiler);
13 |
14 | await server.start();
15 |
16 | const { page, browser } = await runBrowser();
17 |
18 | try {
19 | const pageErrors = [];
20 | const consoleMessages = [];
21 |
22 | page
23 | .on("console", (message) => {
24 | consoleMessages.push(message.text());
25 | })
26 | .on("pageerror", (error) => {
27 | pageErrors.push(error);
28 | });
29 |
30 | await page.goto(`http://127.0.0.1:${port}/test.html`, {
31 | waitUntil: "domcontentloaded",
32 | });
33 | await new Promise((resolve) => {
34 | const interval = setInterval(() => {
35 | if (consoleMessages.includes("Hey.")) {
36 | clearInterval(interval);
37 |
38 | resolve();
39 | }
40 | }, 100);
41 | });
42 |
43 | expect(consoleMessages).toMatchSnapshot("console messages");
44 | expect(pageErrors).toMatchSnapshot("page errors");
45 | } finally {
46 | await browser.close();
47 | await server.stop();
48 | }
49 | });
50 |
51 | it.skip("should work with multiple entries", async () => {
52 | const compiler = webpack(lazyCompilationMultipleEntriesConfig);
53 | const server = new Server({ port }, compiler);
54 |
55 | await server.start();
56 |
57 | const { page, browser } = await runBrowser();
58 |
59 | try {
60 | const pageErrors = [];
61 | const consoleMessages = [];
62 |
63 | page
64 | .on("console", (message) => {
65 | consoleMessages.push(message.text());
66 | })
67 | .on("pageerror", (error) => {
68 | pageErrors.push(error);
69 | });
70 |
71 | await page.goto(`http://127.0.0.1:${port}/test-one.html`, {
72 | waitUntil: "domcontentloaded",
73 | });
74 | await new Promise((resolve) => {
75 | const interval = setInterval(() => {
76 | console.log(consoleMessages);
77 | if (consoleMessages.includes("One.")) {
78 | clearInterval(interval);
79 |
80 | resolve();
81 | }
82 | }, 100);
83 | });
84 |
85 | await page.goto(`http://127.0.0.1:${port}/test-two.html`, {
86 | waitUntil: "domcontentloaded",
87 | });
88 | await new Promise((resolve) => {
89 | const interval = setInterval(() => {
90 | console.log(consoleMessages);
91 | if (consoleMessages.includes("Two.")) {
92 | clearInterval(interval);
93 |
94 | resolve();
95 | }
96 | }, 100);
97 | });
98 |
99 | expect(consoleMessages).toMatchSnapshot("console messages");
100 | expect(pageErrors).toMatchSnapshot("page errors");
101 | } finally {
102 | await browser.close();
103 | await server.stop();
104 | }
105 | });
106 | });
107 |
--------------------------------------------------------------------------------
/tests/e2e/mime-types.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/mime-types-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map")["mime-types-option"];
6 |
7 | describe("mimeTypes option", () => {
8 | describe("as an object with a remapped type", () => {
9 | let compiler;
10 | let server;
11 | let page;
12 | let browser;
13 | let pageErrors;
14 | let consoleMessages;
15 |
16 | beforeEach(async () => {
17 | compiler = webpack(config);
18 |
19 | server = new Server(
20 | {
21 | devMiddleware: {
22 | mimeTypes: {
23 | js: "text/plain",
24 | },
25 | },
26 | port,
27 | },
28 | compiler,
29 | );
30 |
31 | await server.start();
32 |
33 | ({ page, browser } = await runBrowser());
34 |
35 | pageErrors = [];
36 | consoleMessages = [];
37 | });
38 |
39 | afterEach(async () => {
40 | await browser.close();
41 | await server.stop();
42 | });
43 |
44 | it("should request file with different js mime type", async () => {
45 | page
46 | .on("console", (message) => {
47 | consoleMessages.push(message);
48 | })
49 | .on("pageerror", (error) => {
50 | pageErrors.push(error);
51 | });
52 |
53 | const response = await page.goto(`http://127.0.0.1:${port}/main.js`, {
54 | waitUntil: "networkidle0",
55 | });
56 |
57 | expect(response.status()).toMatchSnapshot("response status");
58 |
59 | expect(response.headers()["content-type"]).toMatchSnapshot(
60 | "response headers content-type",
61 | );
62 |
63 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
64 | "console messages",
65 | );
66 |
67 | expect(pageErrors).toMatchSnapshot("page errors");
68 | });
69 | });
70 |
71 | describe("as an object with a custom type", () => {
72 | let compiler;
73 | let server;
74 | let page;
75 | let browser;
76 | let pageErrors;
77 | let consoleMessages;
78 |
79 | beforeEach(async () => {
80 | compiler = webpack(config);
81 |
82 | server = new Server(
83 | {
84 | devMiddleware: {
85 | mimeTypes: {
86 | custom: "text/html",
87 | },
88 | },
89 | port,
90 | },
91 | compiler,
92 | );
93 |
94 | await server.start();
95 |
96 | ({ page, browser } = await runBrowser());
97 |
98 | pageErrors = [];
99 | consoleMessages = [];
100 | });
101 |
102 | afterEach(async () => {
103 | await browser.close();
104 | await server.stop();
105 | });
106 |
107 | it("should request file with different js mime type", async () => {
108 | page
109 | .on("console", (message) => {
110 | consoleMessages.push(message);
111 | })
112 | .on("pageerror", (error) => {
113 | pageErrors.push(error);
114 | });
115 |
116 | const response = await page.goto(`http://127.0.0.1:${port}/file.custom`, {
117 | waitUntil: "networkidle0",
118 | });
119 |
120 | expect(response.status()).toMatchSnapshot("response status");
121 |
122 | expect(response.headers()["content-type"]).toMatchSnapshot(
123 | "response headers content-type",
124 | );
125 |
126 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
127 | "console messages",
128 | );
129 |
130 | expect(pageErrors).toMatchSnapshot("page errors");
131 | });
132 | });
133 | });
134 |
--------------------------------------------------------------------------------
/tests/e2e/on-listening.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/client-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map")["on-listening-option"];
6 |
7 | describe("onListening option", () => {
8 | let compiler;
9 | let server;
10 | let page;
11 | let browser;
12 | let pageErrors;
13 | let consoleMessages;
14 | let onListeningIsRunning = false;
15 |
16 | beforeEach(async () => {
17 | compiler = webpack(config);
18 | server = new Server(
19 | {
20 | onListening: (devServer) => {
21 | if (!devServer) {
22 | throw new Error("webpack-dev-server is not defined");
23 | }
24 |
25 | onListeningIsRunning = true;
26 |
27 | devServer.app.get("/listening/some/path", (_, response) => {
28 | response.send("listening");
29 | });
30 |
31 | devServer.app.post("/listening/some/path", (_, response) => {
32 | response.send("listening POST");
33 | });
34 | },
35 | port,
36 | },
37 | compiler,
38 | );
39 |
40 | await server.start();
41 |
42 | ({ page, browser } = await runBrowser());
43 |
44 | pageErrors = [];
45 | consoleMessages = [];
46 | });
47 |
48 | afterEach(async () => {
49 | await browser.close();
50 | await server.stop();
51 | });
52 |
53 | it("should handle GET request to /listening/some/path route", async () => {
54 | page
55 | .on("console", (message) => {
56 | consoleMessages.push(message);
57 | })
58 | .on("pageerror", (error) => {
59 | pageErrors.push(error);
60 | });
61 |
62 | const response = await page.goto(
63 | `http://127.0.0.1:${port}/listening/some/path`,
64 | {
65 | waitUntil: "networkidle0",
66 | },
67 | );
68 |
69 | expect(onListeningIsRunning).toBe(true);
70 |
71 | expect(response.headers()["content-type"]).toMatchSnapshot(
72 | "response headers content-type",
73 | );
74 |
75 | expect(response.status()).toMatchSnapshot("response status");
76 |
77 | expect(await response.text()).toMatchSnapshot("response text");
78 |
79 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
80 | "console messages",
81 | );
82 |
83 | expect(pageErrors).toMatchSnapshot("page errors");
84 | });
85 |
86 | it("should handle POST request to /listening/some/path route", async () => {
87 | await page.setRequestInterception(true);
88 |
89 | page
90 | .on("console", (message) => {
91 | consoleMessages.push(message);
92 | })
93 | .on("pageerror", (error) => {
94 | pageErrors.push(error);
95 | })
96 | .on("request", (interceptedRequest) => {
97 | if (interceptedRequest.isInterceptResolutionHandled()) return;
98 |
99 | interceptedRequest.continue({ method: "POST" });
100 | });
101 |
102 | const response = await page.goto(
103 | `http://127.0.0.1:${port}/listening/some/path`,
104 | {
105 | waitUntil: "networkidle0",
106 | },
107 | );
108 |
109 | expect(onListeningIsRunning).toBe(true);
110 |
111 | expect(response.headers()["content-type"]).toMatchSnapshot(
112 | "response headers content-type",
113 | );
114 |
115 | expect(response.status()).toMatchSnapshot("response status");
116 |
117 | expect(await response.text()).toMatchSnapshot("response text");
118 |
119 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
120 | "console messages",
121 | );
122 |
123 | expect(pageErrors).toMatchSnapshot("page errors");
124 | });
125 | });
126 |
--------------------------------------------------------------------------------
/tests/e2e/port.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/client-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map").port;
6 |
7 | describe("port", () => {
8 | const ports = [
9 | "",
10 | // eslint-disable-next-line no-undefined
11 | undefined,
12 | "auto",
13 | port,
14 | `${port}`,
15 | 0,
16 | "-1",
17 | "99999",
18 | ];
19 |
20 | for (const testedPort of ports) {
21 | it(`should work using "${testedPort}" port `, async () => {
22 | const compiler = webpack(config);
23 | const devServerOptions = {};
24 |
25 | let usedPort;
26 |
27 | if (
28 | testedPort === "" ||
29 | typeof testedPort === "undefined"
30 | ) {
31 | process.env.WEBPACK_DEV_SERVER_BASE_PORT = port;
32 | usedPort = port;
33 | } else if (testedPort === "auto") {
34 | process.env.WEBPACK_DEV_SERVER_BASE_PORT = port;
35 | devServerOptions.port = testedPort;
36 | usedPort = port;
37 | } else {
38 | devServerOptions.port = testedPort;
39 | usedPort = testedPort;
40 | }
41 |
42 | const server = new Server(devServerOptions, compiler);
43 |
44 | let errored;
45 |
46 | try {
47 | await server.start();
48 | } catch (error) {
49 | errored = error;
50 | }
51 |
52 | if (testedPort === "-1" || testedPort === "99999") {
53 | const errorMessageRegExp = /options.port should be >= 0 and < 65536/;
54 |
55 | try {
56 | expect(errored.message).toMatch(errorMessageRegExp);
57 | } finally {
58 | await server.stop();
59 | }
60 |
61 | return;
62 | }
63 |
64 | const address = server.server.address();
65 |
66 | if (testedPort === 0) {
67 | expect(typeof address.port).toBe("number");
68 | } else {
69 | expect(address.port).toBe(Number(usedPort));
70 | }
71 |
72 | const { page, browser } = await runBrowser();
73 |
74 | try {
75 | const pageErrors = [];
76 | const consoleMessages = [];
77 |
78 | page
79 | .on("console", (message) => {
80 | consoleMessages.push(message);
81 | })
82 | .on("pageerror", (error) => {
83 | pageErrors.push(error);
84 | });
85 |
86 | await page.goto(`http://127.0.0.1:${address.port}/`, {
87 | waitUntil: "networkidle0",
88 | });
89 |
90 | expect(
91 | consoleMessages.map((message) => message.text()),
92 | ).toMatchSnapshot("console messages");
93 | expect(pageErrors).toMatchSnapshot("page errors");
94 | } finally {
95 | await browser.close();
96 | await server.stop();
97 | }
98 |
99 | if (
100 | testedPort === "" ||
101 | typeof testedPort === "undefined"
102 | ) {
103 | process.env.WEBPACK_DEV_SERVER_BASE_PORT = undefined;
104 | }
105 | });
106 | }
107 | });
108 |
--------------------------------------------------------------------------------
/tests/e2e/progress.test.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 | const fs = require("graceful-fs");
3 | const webpack = require("@rspack/core");
4 | const { RspackDevServer: Server } = require("@rspack/dev-server");
5 | const reloadConfig = require("../fixtures/reload-config-2/webpack.config");
6 | const runBrowser = require("../helpers/run-browser");
7 | const port = require("../helpers/ports-map").progress;
8 |
9 | const cssFilePath = path.resolve(
10 | __dirname,
11 | "../fixtures/reload-config-2/main.css",
12 | );
13 |
14 | describe("progress", () => {
15 | it("should work and log progress in a browser console", async () => {
16 | fs.writeFileSync(cssFilePath, "body { background-color: rgb(0, 0, 255); }");
17 |
18 | const compiler = webpack(reloadConfig);
19 | const devServerOptions = {
20 | port,
21 | client: {
22 | progress: true,
23 | },
24 | };
25 | const server = new Server(devServerOptions, compiler);
26 |
27 | await server.start();
28 |
29 | try {
30 | const { page, browser } = await runBrowser();
31 |
32 | const consoleMessages = [];
33 |
34 | try {
35 | let doHotUpdate = false;
36 |
37 | page
38 | .on("console", (message) => {
39 | consoleMessages.push(message);
40 | })
41 | .on("request", (interceptedRequest) => {
42 | if (interceptedRequest.isInterceptResolutionHandled()) return;
43 |
44 | if (/\.hot-update\.(json|js)$/.test(interceptedRequest.url())) {
45 | doHotUpdate = true;
46 | }
47 | });
48 |
49 | await page.goto(`http://localhost:${port}/`, {
50 | waitUntil: "networkidle0",
51 | });
52 |
53 | fs.writeFileSync(
54 | cssFilePath,
55 | "body { background-color: rgb(255, 0, 0); }",
56 | );
57 |
58 | await new Promise((resolve) => {
59 | const timer = setInterval(() => {
60 | if (doHotUpdate) {
61 | clearInterval(timer);
62 |
63 | resolve();
64 | }
65 | }, 100);
66 | });
67 | } finally {
68 | await browser.close();
69 | }
70 |
71 | const progressConsoleMessage = consoleMessages.filter((message) =>
72 | /^\[webpack-dev-server\] (\[[a-zA-Z]+\] )?[0-9]{1,3}% - /.test(
73 | message.text(),
74 | ),
75 | );
76 |
77 | expect(progressConsoleMessage.length > 0).toBe(true);
78 | } finally {
79 | fs.unlinkSync(cssFilePath);
80 |
81 | await server.stop();
82 | }
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/tests/e2e/range-header.test.js:
--------------------------------------------------------------------------------
1 | const request = require("supertest");
2 | const webpack = require("@rspack/core");
3 | const { RspackDevServer: Server } = require("@rspack/dev-server");
4 | const config = require("../fixtures/static-config/webpack.config");
5 | const port = require("../helpers/ports-map")["range-header"];
6 |
7 | describe("'Range' header", () => {
8 | let compiler;
9 | let server;
10 |
11 | beforeAll(async () => {
12 | compiler = webpack(config);
13 |
14 | server = new Server({ port }, compiler);
15 |
16 | await server.start();
17 | });
18 |
19 | afterAll(async () => {
20 | await server.stop();
21 | });
22 |
23 | it('should work with "Range" header using "GET" method', async () => {
24 | const response = await request(server.app).get("/main.js");
25 |
26 | expect(response.status).toBe(200);
27 | expect(response.headers["content-type"]).toBe(
28 | "application/javascript; charset=utf-8",
29 | );
30 | expect(response.headers["accept-ranges"]).toBe("bytes");
31 |
32 | const responseContent = response.text;
33 | const responseRange = await request(server.app)
34 | .get("/main.js")
35 | .set("Range", "bytes=0-499");
36 |
37 | expect(responseRange.status).toBe(206);
38 | expect(responseRange.headers["content-type"]).toBe(
39 | "application/javascript; charset=utf-8",
40 | );
41 | expect(responseRange.headers["content-length"]).toBe("500");
42 | expect(responseRange.headers["content-range"]).toMatch(/^bytes 0-499\//);
43 | expect(responseRange.text).toBe(responseContent.slice(0, 500));
44 | expect(responseRange.text.length).toBe(500);
45 | });
46 |
47 | it('should work with "Range" header using "HEAD" method', async () => {
48 | const response = await request(server.app).head("/main.js");
49 |
50 | expect(response.status).toBe(200);
51 | expect(response.headers["content-type"]).toBe(
52 | "application/javascript; charset=utf-8",
53 | );
54 | expect(response.headers["accept-ranges"]).toBe("bytes");
55 |
56 | const responseRange = await request(server.app)
57 | .head("/main.js")
58 | .set("Range", "bytes=0-499");
59 |
60 | expect(responseRange.status).toBe(206);
61 | expect(responseRange.headers["content-type"]).toBe(
62 | "application/javascript; charset=utf-8",
63 | );
64 | expect(responseRange.headers["content-length"]).toBe("500");
65 | expect(responseRange.headers["content-range"]).toMatch(/^bytes 0-499\//);
66 | });
67 |
68 | it('should work with unsatisfiable "Range" header using "GET" method', async () => {
69 | const response = await request(server.app).get("/main.js");
70 |
71 | expect(response.status).toBe(200);
72 | expect(response.headers["content-type"]).toBe(
73 | "application/javascript; charset=utf-8",
74 | );
75 | expect(response.headers["accept-ranges"]).toBe("bytes");
76 |
77 | const responseRange = await request(server.app)
78 | .get("/main.js")
79 | .set("Range", "bytes=99999999999-");
80 |
81 | expect(responseRange.status).toBe(416);
82 | expect(responseRange.headers["content-type"]).toBe(
83 | "text/html; charset=utf-8",
84 | );
85 | expect(responseRange.headers["content-range"]).toMatch(/^bytes \*\//);
86 | });
87 |
88 | it('should work with malformed "Range" header using "GET" method', async () => {
89 | const response = await request(server.app).get("/main.js");
90 |
91 | expect(response.status).toBe(200);
92 | expect(response.headers["content-type"]).toBe(
93 | "application/javascript; charset=utf-8",
94 | );
95 | expect(response.headers["accept-ranges"]).toBe("bytes");
96 |
97 | const responseContent = response.text;
98 | const responseRange = await request(server.app)
99 | .get("/main.js")
100 | .set("Range", "bytes");
101 |
102 | expect(responseRange.status).toBe(200);
103 | expect(responseRange.headers["content-type"]).toBe(
104 | "application/javascript; charset=utf-8",
105 | );
106 | expect(responseRange.text).toBe(responseContent);
107 | expect(responseRange.text.length).toBe(responseContent.length);
108 | });
109 | });
110 |
--------------------------------------------------------------------------------
/tests/e2e/setup-exit-signals.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/simple-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map")["setup-exit-signals-option"];
6 |
7 | describe("setupExitSignals option", () => {
8 | describe("should handle 'SIGINT' and 'SIGTERM' signals", () => {
9 | let compiler;
10 | let server;
11 | let page;
12 | let browser;
13 | let pageErrors;
14 | let consoleMessages;
15 | let doExit;
16 | let exitSpy;
17 | let stopCallbackSpy;
18 | let stdinResumeSpy;
19 | let closeCallbackSpy;
20 |
21 | const signals = ["SIGINT", "SIGTERM"];
22 |
23 | beforeEach(async () => {
24 | compiler = webpack(config);
25 |
26 | server = new Server(
27 | {
28 | setupExitSignals: true,
29 | port,
30 | },
31 | compiler,
32 | );
33 |
34 | await server.start();
35 |
36 | ({ page, browser } = await runBrowser());
37 |
38 | pageErrors = [];
39 | consoleMessages = [];
40 | doExit = false;
41 |
42 | exitSpy = jest.spyOn(process, "exit").mockImplementation(() => {
43 | doExit = true;
44 | });
45 |
46 | stdinResumeSpy = jest
47 | .spyOn(process.stdin, "resume")
48 | .mockImplementation(() => {});
49 |
50 | stopCallbackSpy = jest.spyOn(server, "stopCallback");
51 |
52 | if (server.compiler.close) {
53 | closeCallbackSpy = jest.spyOn(server.compiler, "close");
54 | }
55 | });
56 |
57 | afterEach(async () => {
58 | exitSpy.mockReset();
59 | stdinResumeSpy.mockReset();
60 | for (const signal of signals) {
61 | process.removeAllListeners(signal);
62 | }
63 | process.stdin.removeAllListeners("end");
64 | await browser.close();
65 | await server.stop();
66 | });
67 |
68 | it.each(signals)("should close and exit on %s", async (signal) => {
69 | page
70 | .on("console", (message) => {
71 | consoleMessages.push(message);
72 | })
73 | .on("pageerror", (error) => {
74 | pageErrors.push(error);
75 | });
76 |
77 | const response = await page.goto(`http://127.0.0.1:${port}/`, {
78 | waitUntil: "networkidle0",
79 | });
80 |
81 | expect(response.status()).toMatchSnapshot("response status");
82 |
83 | process.emit(signal);
84 |
85 | await new Promise((resolve) => {
86 | const interval = setInterval(() => {
87 | if (doExit) {
88 | expect(stopCallbackSpy.mock.calls.length).toEqual(1);
89 |
90 | if (server.compiler.close) {
91 | expect(closeCallbackSpy.mock.calls.length).toEqual(1);
92 | }
93 |
94 | clearInterval(interval);
95 |
96 | resolve();
97 | }
98 | }, 100);
99 | });
100 |
101 | consoleMessages = consoleMessages.filter(
102 | (message) =>
103 | !(
104 | message.text().includes("Trying to reconnect...") ||
105 | message.text().includes("Disconnected")
106 | ),
107 | );
108 |
109 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
110 | "console messages",
111 | );
112 |
113 | expect(pageErrors).toMatchSnapshot("page errors");
114 | });
115 | });
116 | });
117 |
--------------------------------------------------------------------------------
/tests/e2e/setup-middlewares.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/client-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const port = require("../helpers/ports-map")["setup-middlewares-option"];
6 |
7 | describe("setupMiddlewares option", () => {
8 | let compiler;
9 | let server;
10 | let page;
11 | let browser;
12 | let pageErrors;
13 | let consoleMessages;
14 |
15 | beforeEach(async () => {
16 | compiler = webpack(config);
17 | server = new Server(
18 | {
19 | setupMiddlewares: (middlewares, devServer) => {
20 | if (!devServer) {
21 | throw new Error("webpack-dev-server is not defined");
22 | }
23 |
24 | devServer.app.use("/setup-middleware/some/path", (req, res, next) => {
25 | if (req.method === "GET") {
26 | res.setHeader("Content-Type", "text/html; charset=utf-8");
27 | res.end("setup-middlewares option GET");
28 | return;
29 | }
30 | if (req.method === "POST") {
31 | res.setHeader("Content-Type", "text/html; charset=utf-8");
32 | res.end("setup-middlewares option POST");
33 | return;
34 | }
35 |
36 | return next();
37 | });
38 |
39 | middlewares.push({
40 | name: "hello-world-test-two",
41 | middleware: (req, res, next) => {
42 | if (req.url !== "/foo/bar/baz") {
43 | next();
44 |
45 | return;
46 | }
47 |
48 | res.setHeader("Content-Type", "text/html; charset=utf-8");
49 | res.end("Hello World without path!");
50 | },
51 | });
52 | middlewares.push({
53 | name: "hello-world-test-one",
54 | path: "/foo/bar",
55 | middleware: (req, res) => {
56 | res.setHeader("Content-Type", "text/html; charset=utf-8");
57 | res.end("Hello World with path!");
58 | },
59 | });
60 | middlewares.push((req, res) => {
61 | res.setHeader("Content-Type", "text/html; charset=utf-8");
62 | res.end("Hello World as function!");
63 | });
64 |
65 | return middlewares;
66 | },
67 | port,
68 | },
69 | compiler,
70 | );
71 |
72 | await server.start();
73 |
74 | ({ page, browser } = await runBrowser());
75 |
76 | pageErrors = [];
77 | consoleMessages = [];
78 | });
79 |
80 | afterEach(async () => {
81 | await browser.close();
82 | await server.stop();
83 | });
84 |
85 | it("should handle GET request to /setup-middleware/some/path route", async () => {
86 | page
87 | .on("console", (message) => {
88 | consoleMessages.push(message);
89 | })
90 | .on("pageerror", (error) => {
91 | pageErrors.push(error);
92 | });
93 |
94 | const response = await page.goto(
95 | `http://127.0.0.1:${port}/setup-middleware/some/path`,
96 | {
97 | waitUntil: "networkidle0",
98 | },
99 | );
100 |
101 | expect(response.headers()["content-type"]).toMatchSnapshot(
102 | "response headers content-type",
103 | );
104 | expect(response.status()).toMatchSnapshot("response status");
105 | expect(await response.text()).toMatchSnapshot("response text");
106 |
107 | const response1 = await page.goto(`http://127.0.0.1:${port}/foo/bar`, {
108 | waitUntil: "networkidle0",
109 | });
110 |
111 | expect(response1.headers()["content-type"]).toMatchSnapshot(
112 | "response headers content-type",
113 | );
114 | expect(response1.status()).toMatchSnapshot("response status");
115 | expect(await response1.text()).toMatchSnapshot("response text");
116 |
117 | const response2 = await page.goto(`http://127.0.0.1:${port}/foo/bar/baz`, {
118 | waitUntil: "networkidle0",
119 | });
120 |
121 | expect(response2.headers()["content-type"]).toMatchSnapshot(
122 | "response headers content-type",
123 | );
124 | expect(response2.status()).toMatchSnapshot("response status");
125 | expect(await response2.text()).toMatchSnapshot("response text");
126 |
127 | const response3 = await page.goto(
128 | `http://127.0.0.1:${port}/setup-middleware/unknown`,
129 | {
130 | waitUntil: "networkidle0",
131 | },
132 | );
133 |
134 | expect(response3.headers()["content-type"]).toMatchSnapshot(
135 | "response headers content-type",
136 | );
137 | expect(response3.status()).toMatchSnapshot("response status");
138 | expect(await response3.text()).toMatchSnapshot("response text");
139 |
140 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
141 | "console messages",
142 | );
143 | expect(pageErrors).toMatchSnapshot("page errors");
144 | });
145 |
146 | it("should handle POST request to /setup-middleware/some/path route", async () => {
147 | await page.setRequestInterception(true);
148 |
149 | page
150 | .on("console", (message) => {
151 | consoleMessages.push(message);
152 | })
153 | .on("pageerror", (error) => {
154 | pageErrors.push(error);
155 | })
156 | .on("request", (interceptedRequest) => {
157 | if (interceptedRequest.isInterceptResolutionHandled()) return;
158 |
159 | interceptedRequest.continue({ method: "POST" });
160 | });
161 |
162 | const response = await page.goto(
163 | `http://127.0.0.1:${port}/setup-middleware/some/path`,
164 | {
165 | waitUntil: "networkidle0",
166 | },
167 | );
168 |
169 | expect(response.headers()["content-type"]).toMatchSnapshot(
170 | "response headers content-type",
171 | );
172 | expect(response.status()).toMatchSnapshot("response status");
173 | expect(await response.text()).toMatchSnapshot("response text");
174 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
175 | "console messages",
176 | );
177 | expect(pageErrors).toMatchSnapshot("page errors");
178 | });
179 | });
180 |
--------------------------------------------------------------------------------
/tests/e2e/stats.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/client-config/webpack.config");
4 | const HTMLGeneratorPlugin = require("../helpers/html-generator-plugin");
5 | const runBrowser = require("../helpers/run-browser");
6 | const port = require("../helpers/ports-map").stats;
7 |
8 | global.console.log = jest.fn();
9 |
10 | describe("stats", () => {
11 | const cases = [
12 | {
13 | title: 'should work when "stats" is not specified',
14 | webpackOptions: {},
15 | },
16 | {
17 | title: 'should work using "{}" value for the "stats" option',
18 | webpackOptions: {
19 | stats: {},
20 | },
21 | },
22 | {
23 | title: 'should work using "undefined" value for the "stats" option',
24 | webpackOptions: {
25 | // eslint-disable-next-line no-undefined
26 | stats: undefined,
27 | },
28 | },
29 | {
30 | title: 'should work using "false" value for the "stats" option',
31 | webpackOptions: {
32 | stats: false,
33 | },
34 | },
35 | {
36 | title: 'should work using "errors-only" value for the "stats" option',
37 | webpackOptions: {
38 | stats: "errors-only",
39 | },
40 | },
41 | {
42 | title:
43 | 'should work using "{ assets: false }" value for the "stats" option',
44 | webpackOptions: {
45 | stats: {
46 | assets: false,
47 | },
48 | },
49 | },
50 | // TODO: support object `config.stats.colors`
51 | // {
52 | // title:
53 | // 'should work using "{ assets: false }" value for the "stats" option',
54 | // webpackOptions: {
55 | // stats: {
56 | // colors: {
57 | // green: "\u001b[32m",
58 | // },
59 | // },
60 | // },
61 | // },
62 | // `config.stats.warningsFilter` is deprecated in favor of config.ignoreWarnings
63 | // {
64 | // title:
65 | // 'should work using "{ warningsFilter: \'test\' }" value for the "stats" option',
66 | // webpackOptions: {
67 | // plugins: [
68 | // {
69 | // apply(compiler) {
70 | // compiler.hooks.thisCompilation.tap(
71 | // "warnings-webpack-plugin",
72 | // (compilation) => {
73 | // compilation.warnings.push(
74 | // new Error("Warning from compilation"),
75 | // );
76 | // },
77 | // );
78 | // },
79 | // },
80 | // new HTMLGeneratorPlugin(),
81 | // ],
82 | // stats: { warningsFilter: /Warning from compilation/ },
83 | // },
84 | // },
85 | ];
86 |
87 | if (webpack.version.startsWith("5")) {
88 | cases.push({
89 | title: 'should work and respect the "ignoreWarnings" option',
90 | webpackOptions: {
91 | plugins: [
92 | {
93 | apply(compiler) {
94 | compiler.hooks.thisCompilation.tap(
95 | "warnings-webpack-plugin",
96 | (compilation) => {
97 | compilation.warnings.push(
98 | new Error("Warning from compilation"),
99 | );
100 | },
101 | );
102 | },
103 | },
104 | new HTMLGeneratorPlugin(),
105 | ],
106 | ignoreWarnings: [/Warning from compilation/],
107 | },
108 | });
109 | }
110 |
111 | for (const testCase of cases) {
112 | it(testCase.title, async () => {
113 | const compiler = webpack({ ...config, ...testCase.webpackOptions });
114 | const devServerOptions = {
115 | port,
116 | };
117 | const server = new Server(devServerOptions, compiler);
118 |
119 | await server.start();
120 |
121 | const { page, browser } = await runBrowser();
122 |
123 | try {
124 | const consoleMessages = [];
125 |
126 | page.on("console", (message) => {
127 | consoleMessages.push(message);
128 | });
129 |
130 | await page.goto(`http://localhost:${port}/`, {
131 | waitUntil: "networkidle0",
132 | });
133 |
134 | expect(
135 | consoleMessages.map((message) => message.text()),
136 | ).toMatchSnapshot();
137 | } finally {
138 | await browser.close();
139 | await server.stop();
140 | }
141 | });
142 | }
143 | });
144 |
--------------------------------------------------------------------------------
/tests/e2e/target.test.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 | const webpack = require("@rspack/core");
3 | const { RspackDevServer: Server } = require("@rspack/dev-server");
4 | const config = require("../fixtures/client-config/webpack.config");
5 | const runBrowser = require("../helpers/run-browser");
6 | const port = require("../helpers/ports-map").target;
7 | const workerConfig = require("../fixtures/worker-config/webpack.config");
8 | const workerConfigDevServerFalse = require("../fixtures/worker-config-dev-server-false/webpack.config");
9 |
10 | const sortByTerm = (data, term) =>
11 | data.sort((a, b) => (a.indexOf(term) < b.indexOf(term) ? -1 : 1));
12 |
13 | describe("target", () => {
14 | const targets = [
15 | false,
16 | "browserslist:defaults",
17 | "web",
18 | "webworker",
19 | "node",
20 | "async-node",
21 | "electron-main",
22 | "electron-preload",
23 | "electron-renderer",
24 | "nwjs",
25 | "node-webkit",
26 | "es5",
27 | ["web", "es5"],
28 | ];
29 |
30 | for (const target of targets) {
31 | it(`should work using "${target}" target`, async () => {
32 | const compiler = webpack({
33 | ...config,
34 | target,
35 | ...(target === false || target === "es5"
36 | ? {
37 | output: { chunkFormat: "array-push", path: "/" },
38 | }
39 | : {}),
40 | });
41 | const server = new Server({ port }, compiler);
42 |
43 | await server.start();
44 |
45 | const { page, browser } = await runBrowser();
46 |
47 | try {
48 | const pageErrors = [];
49 | const consoleMessages = [];
50 |
51 | page
52 | .on("console", (message) => {
53 | consoleMessages.push(message);
54 | })
55 | .on("pageerror", (error) => {
56 | pageErrors.push(error);
57 | });
58 |
59 | await page.goto(`http://127.0.0.1:${port}/`, {
60 | waitUntil: "networkidle0",
61 | });
62 |
63 | expect(
64 | consoleMessages.map((message) => message.text()),
65 | ).toMatchSnapshot("console messages");
66 |
67 | // TODO: check why require is defined in theses target
68 | // if (
69 | // target === "node" ||
70 | // target === "async-node" ||
71 | // target === "electron-main" ||
72 | // target === "electron-preload" ||
73 | // target === "electron-renderer" ||
74 | // target === "nwjs" ||
75 | // target === "node-webkit"
76 | // ) {
77 | // console.log(pageErrors);
78 | // const hasRequireOrGlobalError =
79 | // pageErrors.filter((pageError) =>
80 | // /require is not defined|global is not defined/.test(pageError),
81 | // ).length === 1;
82 |
83 | // expect(hasRequireOrGlobalError).toBe(true);
84 | // } else {
85 | // expect(pageErrors).toMatchSnapshot("page errors");
86 | // }
87 | } finally {
88 | await browser.close();
89 | await server.stop();
90 | }
91 | });
92 | }
93 |
94 | it("should work using multi compiler mode with `web` and `webworker` targets", async () => {
95 | const compiler = webpack(workerConfig);
96 | const server = new Server({ port }, compiler);
97 |
98 | await server.start();
99 |
100 | const { page, browser } = await runBrowser();
101 |
102 | try {
103 | const pageErrors = [];
104 | const consoleMessages = [];
105 |
106 | page
107 | .on("console", (message) => {
108 | consoleMessages.push(message);
109 | })
110 | .on("pageerror", (error) => {
111 | pageErrors.push(error);
112 | });
113 |
114 | await page.goto(`http://127.0.0.1:${port}/`, {
115 | waitUntil: "networkidle0",
116 | });
117 |
118 | expect(
119 | sortByTerm(
120 | consoleMessages.map((message) => message.text()),
121 | "Worker said:",
122 | ),
123 | ).toMatchSnapshot("console messages");
124 |
125 | expect(pageErrors).toMatchSnapshot("page errors");
126 | } finally {
127 | await browser.close();
128 | await server.stop();
129 | }
130 | });
131 |
132 | it("should work using multi compiler mode with `web` and `webworker` targets with `devServer: false`", async () => {
133 | const compiler = webpack(workerConfigDevServerFalse);
134 | const server = new Server(
135 | {
136 | port,
137 | static: {
138 | directory: path.resolve(
139 | __dirname,
140 | "../fixtures/worker-config-dev-server-false/public/",
141 | ),
142 | },
143 | },
144 | compiler,
145 | );
146 |
147 | await server.start();
148 |
149 | const { page, browser } = await runBrowser();
150 |
151 | try {
152 | const pageErrors = [];
153 | const consoleMessages = [];
154 |
155 | page
156 | .on("console", (message) => {
157 | consoleMessages.push(message);
158 | })
159 | .on("pageerror", (error) => {
160 | pageErrors.push(error);
161 | });
162 |
163 | await page.goto(`http://127.0.0.1:${port}/`, {
164 | waitUntil: "networkidle0",
165 | });
166 |
167 | expect(
168 | sortByTerm(
169 | consoleMessages.map((message) => message.text()),
170 | "Worker said:",
171 | ),
172 | ).toMatchSnapshot("console messages");
173 |
174 | expect(pageErrors).toMatchSnapshot("page errors");
175 | } finally {
176 | await browser.close();
177 | await server.stop();
178 | }
179 | });
180 | });
181 |
--------------------------------------------------------------------------------
/tests/e2e/web-socket-server.test.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 | const config = require("../fixtures/client-config/webpack.config");
4 | const runBrowser = require("../helpers/run-browser");
5 | const sessionSubscribe = require("../helpers/session-subscribe");
6 | const port = require("../helpers/ports-map")["web-socket-server-test"];
7 |
8 | describe("web socket server", () => {
9 | it("should work allow to disable", async () => {
10 | const devServerPort = port;
11 |
12 | const compiler = webpack(config);
13 | const devServerOptions = {
14 | webSocketServer: false,
15 | port: devServerPort,
16 | };
17 | const server = new Server(devServerOptions, compiler);
18 |
19 | await server.start();
20 |
21 | const { page, browser } = await runBrowser();
22 |
23 | try {
24 | const pageErrors = [];
25 | const consoleMessages = [];
26 |
27 | page
28 | .on("console", (message) => {
29 | consoleMessages.push(message);
30 | })
31 | .on("pageerror", (error) => {
32 | pageErrors.push(error);
33 | });
34 |
35 | const webSocketRequests = [];
36 | const session = await page.target().createCDPSession();
37 |
38 | session.on("Network.webSocketCreated", (test) => {
39 | webSocketRequests.push(test);
40 | });
41 |
42 | await session.send("Target.setAutoAttach", {
43 | autoAttach: true,
44 | flatten: true,
45 | waitForDebuggerOnStart: true,
46 | });
47 |
48 | sessionSubscribe(session);
49 |
50 | await page.goto(`http://127.0.0.1:${port}/`, {
51 | waitUntil: "networkidle0",
52 | });
53 |
54 | expect(webSocketRequests).toHaveLength(0);
55 | expect(consoleMessages.map((message) => message.text())).toMatchSnapshot(
56 | "console messages",
57 | );
58 | expect(pageErrors).toMatchSnapshot("page errors");
59 | } finally {
60 | await browser.close();
61 | await server.stop();
62 | }
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/tests/fixtures/client-config/bar.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Bar.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/client-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/client-config/index.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/tests/fixtures/client-config/static/foo.txt:
--------------------------------------------------------------------------------
1 | Text
--------------------------------------------------------------------------------
/tests/fixtures/client-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | devtool: false,
7 | mode: "development",
8 | context: __dirname,
9 | stats: "none",
10 | entry: "./foo.js",
11 | output: {
12 | path: "/"
13 | },
14 | infrastructureLogging: {
15 | level: "info",
16 | stream: {
17 | write: () => {}
18 | }
19 | },
20 | plugins: [new HTMLGeneratorPlugin()]
21 | };
22 |
--------------------------------------------------------------------------------
/tests/fixtures/custom-client/CustomClientEntry.js:
--------------------------------------------------------------------------------
1 | console.log("custom client entry");
2 |
--------------------------------------------------------------------------------
/tests/fixtures/custom-client/CustomClientHotEntry.js:
--------------------------------------------------------------------------------
1 | console.log("custom client hot entry");
2 |
--------------------------------------------------------------------------------
/tests/fixtures/custom-client/CustomSockJSClient.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copy from webpack-dev-server
3 | */
4 |
5 | "use strict";
6 |
7 | const SockJS = require("sockjs-client/dist/sockjs");
8 |
9 | module.exports = class SockJSClient {
10 | constructor(url) {
11 | this.sock = new SockJS(
12 | url.replace(/^ws:/i, "http://").replace(/^wss:/i, "https://")
13 | );
14 | }
15 |
16 | onOpen(f) {
17 | this.sock.onopen = () => {
18 | console.log("open");
19 | f();
20 | };
21 | }
22 |
23 | onClose(f) {
24 | this.sock.onclose = () => {
25 | console.log("close");
26 | f();
27 | };
28 | }
29 |
30 | // call f with the message string as the first argument
31 | onMessage(f) {
32 | this.sock.onmessage = e => {
33 | const obj = JSON.parse(e.data);
34 | console.log(obj.type);
35 | f(e.data);
36 | };
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-2-config/bar.html:
--------------------------------------------------------------------------------
1 | Foobar
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-2-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-2-config/other.html:
--------------------------------------------------------------------------------
1 | Other file
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-2-config/random-file.txt:
--------------------------------------------------------------------------------
1 | Random file
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-2-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | mode: "development",
5 | context: __dirname,
6 | stats: "none",
7 | entry: "./foo.js",
8 | output: {
9 | path: "/"
10 | },
11 | infrastructureLogging: {
12 | level: "warn"
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-3-config/bar.html:
--------------------------------------------------------------------------------
1 | In-memory file
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-3-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("./bar.html");
4 |
5 | console.log("Hey.");
6 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-3-config/index.html:
--------------------------------------------------------------------------------
1 | static file
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-3-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const moduleRuleForHTML = {
4 | test: /\.html$/,
5 | type: "asset/resource",
6 | generator: {
7 | filename: "index.html"
8 | }
9 | };
10 |
11 | module.exports = {
12 | mode: "development",
13 | context: __dirname,
14 | stats: "none",
15 | entry: "./foo.js",
16 | output: {
17 | path: "/"
18 | },
19 | module: {
20 | rules: [
21 | {
22 | ...moduleRuleForHTML
23 | }
24 | ]
25 | },
26 | infrastructureLogging: {
27 | level: "warn"
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-config/bar.html:
--------------------------------------------------------------------------------
1 | Foobar
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("./index.html");
4 | require("./bar.html");
5 |
6 | console.log("Hey.");
7 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-config/index.html:
--------------------------------------------------------------------------------
1 | Heyyy
2 |
--------------------------------------------------------------------------------
/tests/fixtures/historyapifallback-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const moduleRuleForHTML = {
4 | test: /\.html$/,
5 | type: "asset/resource",
6 | generator: {
7 | filename: "[name][ext]"
8 | }
9 | };
10 |
11 | module.exports = {
12 | mode: "development",
13 | context: __dirname,
14 | stats: "none",
15 | entry: "./foo.js",
16 | output: {
17 | path: "/"
18 | },
19 | module: {
20 | rules: [
21 | {
22 | ...moduleRuleForHTML
23 | }
24 | ]
25 | },
26 | infrastructureLogging: {
27 | level: "warn"
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/ca-symlink.pem:
--------------------------------------------------------------------------------
1 | ca.pem
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/ca.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpQIBAAKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kv
3 | C/hf5Ei1J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYu
4 | Dy9WkFuMie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhs
5 | EENnH6sUE9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2sw
6 | duxJTWRINmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+
7 | T8emgklStASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABAoIBAGqWKPE1QnT3T+3J
8 | G+ITz9P0dDFbvWltlTZmeSJh/s2q+WZloUNtBxdmwbqT/1QecnkyGgyzVCjvSKsu
9 | CgVjWNVAhysgtNtxRT4BVflffBXLVH2qsBjpsLRGU6EcMXuPGTiEp3YRHNuO6Aj8
10 | oP8fEsCGPc9DlJMGgxQRAKlrVF8TN/0j6Qk+YpS4MZ0YFQfBY+WdKu04Z8TVTplQ
11 | tTkiGpBI+Oj85jF59aQiizglJgADkAZ6zmbrctm/G9jPxh7JLS2cKI0ECZgK5yAc
12 | pk10E1YWhoCksjr9arxy6fS9TiX9P15vv06k+s7c4c5X7XDm3X0GWeSbqBMJb8q7
13 | BhZQNzECgYEA4kAtymDBvFYiZFq7+lzQBRKAI1RCq7YqxlieumH0PSkie2bba3dW
14 | NVdTi7at8+GDB9/cHUPKzg/skfJllek57MZmusiVwB/Lmp/IlW8YyGShdYZ7zQsV
15 | KMWJljpky3BEDM5sb08wIkfrOkelI/S4Bqqabd9JzOMJzoTiVOlMam8CgYEA3ctN
16 | yonWz2bsnCUstQvQCLdI5a8Q7GJvlH2awephxGXIKGUuRmyyop0AnRnIBEWtOQV7
17 | yZjW32bU+Wt+2BJ247EyJiIQ4gT+T51t+v/Wt1YNbL3dSj9ttOvwYd4H2W4E7EIO
18 | GKIF4I39FM7r8NfG7YE7S1aVcnrqs01N3nhd9HMCgYEAjepbzpmqbAxLPk97oase
19 | AFB+d6qetz5ozklAJwDSRprKukTmVR5hwMup5/UKX/OQURwl4WVojKCIb3NwLPxC
20 | DTbVsUuoQv6uo6qeEr3A+dHFRQa6GP9eolhl2Ql/t+wPg0jn01oEgzxBXCkceNVD
21 | qUrR2yE4FYBD4nqPzVsZR5kCgYEA1yTi7NkQeldIpZ6Z43T18753A/Xx4JsLyWqd
22 | uAT3mV9x7V1Yqg++qGbLtZjQoPRFt85N6ZxMsqA5b0iK3mXq1auJDdx1rAlT9z6q
23 | 9JM/YNAkbZsvEVq9vIYxw31w98T1GYhpzBM+yDhzir+9tv5YhQKa1dXDWi1JhWwz
24 | YN45pWkCgYEAxuVsJ4D4Th5o050ppWpnxM/WuMhIUKqaoFTVucMKFzn+g24y9pv5
25 | miYdNYIk4Y+4pzHG6ZGZSHJcQ9BLui6H/nLQnqkgCb2lT5nfp7/GKdus7BdcjPGs
26 | fcV46yL7/X0m8nDb3hkwwrDTU4mKFkMrzKpjdZBsttEmW0Aw/3y36gU=
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/server-symlink.crt:
--------------------------------------------------------------------------------
1 | server.crt
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/server-symlink.key:
--------------------------------------------------------------------------------
1 | server.key
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/server-symlink.pfx:
--------------------------------------------------------------------------------
1 | server.pfx
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/server.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDXTCCAkWgAwIBAgIJALz8gD/gAt0OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
4 | aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDIzMTgyMTQ5WhcNMTkxMDIzMTgyMTQ5WjBF
5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
7 | CgKCAQEAxAUVLFM+K3XDLQkBi7xt0s1Ip7JoHYDskzUDQNHjjMkUq5kvC/hf5Ei1
8 | J6qruJs3Xqg86Nl4+ed4ynUajAkRRibhp0P1SG1tgPssIK6iC7g8heYuDy9WkFuM
9 | ie0513zjSn6bMEAK5TegxYAWCbaCZX/Fw9bDniabL/zuOv4sf8J4EPhsEENnH6sU
10 | E9HxPUgQmNt1Tbd0j1Cd5PXrSTLyfVPRh0m9QhXTUHuxsse8XSn9U2swduxJTWRI
11 | NmhffYn+O7kbJGI77xYr8u58Rsf3HCMI8DTKZNvQLChvvtLJ9ckyu7Q+T8emgklS
12 | tASm3V2UtnriaK/IQEhgSdxqVRib3QIDAQABo1AwTjAdBgNVHQ4EFgQUDZBhVKdb
13 | 3BRhLIhuuE522Vsul0IwHwYDVR0jBBgwFoAUDZBhVKdb3BRhLIhuuE522Vsul0Iw
14 | DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABh9WWZwWLgb9/DcTxL72
15 | 6pI96t4jiF79Q+pPefkaIIi0mE6yodWrTAsBQu9I6bNRaEcCSoiXkP2bqskD/UGg
16 | LwUFgSrDOAA3UjdHw3QU5g2NocduG7mcFwA40TB98sOsxsUyYlzSyWzoiQWwPYwb
17 | hek1djuWkqPXsTjlj54PTPN/SjTFmo4p5Ip6nbRf2nOREl7v0rJpGbJvXiCMYyd+
18 | Zv+j4mRjCGo8ysMR2HjCUGkYReLAgKyyz3M7i8vevJhKslyOmy6Txn4F0nPVumaU
19 | DDIy4xXPW1STWfsmSYJfYW3wa0wk+pJQ3j2cTzkPQQ8gwpvM3U9DJl43uwb37v6I
20 | 7Q==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/server.key:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEBRUsUz4rdcMt
3 | CQGLvG3SzUinsmgdgOyTNQNA0eOMyRSrmS8L+F/kSLUnqqu4mzdeqDzo2Xj553jK
4 | dRqMCRFGJuGnQ/VIbW2A+ywgrqILuDyF5i4PL1aQW4yJ7TnXfONKfpswQArlN6DF
5 | gBYJtoJlf8XD1sOeJpsv/O46/ix/wngQ+GwQQ2cfqxQT0fE9SBCY23VNt3SPUJ3k
6 | 9etJMvJ9U9GHSb1CFdNQe7Gyx7xdKf1TazB27ElNZEg2aF99if47uRskYjvvFivy
7 | 7nxGx/ccIwjwNMpk29AsKG++0sn1yTK7tD5Px6aCSVK0BKbdXZS2euJor8hASGBJ
8 | 3GpVGJvdAgMBAAECggEAapYo8TVCdPdP7ckb4hPP0/R0MVu9aW2VNmZ5ImH+zar5
9 | ZmWhQ20HF2bBupP/VB5yeTIaDLNUKO9Iqy4KBWNY1UCHKyC023FFPgFV+V98FctU
10 | faqwGOmwtEZToRwxe48ZOISndhEc247oCPyg/x8SwIY9z0OUkwaDFBEAqWtUXxM3
11 | /SPpCT5ilLgxnRgVB8Fj5Z0q7ThnxNVOmVC1OSIakEj46PzmMXn1pCKLOCUmAAOQ
12 | BnrOZuty2b8b2M/GHsktLZwojQQJmArnIBymTXQTVhaGgKSyOv1qvHLp9L1OJf0/
13 | Xm+/TqT6ztzhzlftcObdfQZZ5JuoEwlvyrsGFlA3MQKBgQDiQC3KYMG8ViJkWrv6
14 | XNAFEoAjVEKrtirGWJ66YfQ9KSJ7Zttrd1Y1V1OLtq3z4YMH39wdQ8rOD+yR8mWV
15 | 6Tnsxma6yJXAH8uan8iVbxjIZKF1hnvNCxUoxYmWOmTLcEQMzmxvTzAiR+s6R6Uj
16 | 9LgGqppt30nM4wnOhOJU6UxqbwKBgQDdy03KidbPZuycJSy1C9AIt0jlrxDsYm+U
17 | fZrB6mHEZcgoZS5GbLKinQCdGcgERa05BXvJmNbfZtT5a37YEnbjsTImIhDiBP5P
18 | nW36/9a3Vg1svd1KP2206/Bh3gfZbgTsQg4YogXgjf0Uzuvw18btgTtLVpVyeuqz
19 | TU3eeF30cwKBgQCN6lvOmapsDEs+T3uhqx4AUH53qp63PmjOSUAnANJGmsq6ROZV
20 | HmHAy6nn9Qpf85BRHCXhZWiMoIhvc3As/EINNtWxS6hC/q6jqp4SvcD50cVFBroY
21 | /16iWGXZCX+37A+DSOfTWgSDPEFcKRx41UOpStHbITgVgEPieo/NWxlHmQKBgQDX
22 | JOLs2RB6V0ilnpnjdPXzvncD9fHgmwvJap24BPeZX3HtXViqD76oZsu1mNCg9EW3
23 | zk3pnEyyoDlvSIreZerVq4kN3HWsCVP3Pqr0kz9g0CRtmy8RWr28hjHDfXD3xPUZ
24 | iGnMEz7IOHOKv722/liFAprV1cNaLUmFbDNg3jmlaQKBgQDG5WwngPhOHmjTnSml
25 | amfEz9a4yEhQqpqgVNW5wwoXOf6DbjL2m/maJh01giThj7inMcbpkZlIclxD0Eu6
26 | Lof+ctCeqSAJvaVPmd+nv8Yp26zsF1yM8ax9xXjrIvv9fSbycNveGTDCsNNTiYoW
27 | QyvMqmN1kGy20SZbQDD/fLfqBQ==
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/tests/fixtures/https-certificate/server.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/https-certificate/server.pfx
--------------------------------------------------------------------------------
/tests/fixtures/lazy-compilation-multiple-entries/one.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("One.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/lazy-compilation-multiple-entries/two.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Two.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/lazy-compilation-multiple-entries/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const oneHTMLContent = `
4 |
5 |
6 |
7 |
8 | test
9 |
10 |
11 |
12 |
13 | `;
14 | const twoHTMLContent = `
15 |
16 |
17 |
18 |
19 | test
20 |
21 |
22 |
23 |
24 | `;
25 |
26 | module.exports = {
27 | devtool: false,
28 | mode: "development",
29 | context: __dirname,
30 | stats: "none",
31 | entry: {
32 | one: "./one.js",
33 | two: "./two.js"
34 | },
35 | output: {
36 | path: "/"
37 | },
38 | experiments: {
39 | lazyCompilation: true
40 | },
41 | infrastructureLogging: {
42 | level: "info",
43 | stream: {
44 | write: () => {}
45 | }
46 | },
47 | plugins: [
48 | {
49 | apply(compiler) {
50 | const pluginName = "html-generator-plugin-test";
51 | const oneFilename = "test-one.html";
52 | const twoFilename = "test-two.html";
53 |
54 | compiler.hooks.thisCompilation.tap(pluginName, compilation => {
55 | const { RawSource } = compiler.webpack.sources;
56 |
57 | compilation.hooks.processAssets.tap(
58 | {
59 | name: pluginName,
60 | stage:
61 | compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
62 | },
63 | () => {
64 | const oneSource = new RawSource(oneHTMLContent);
65 |
66 | compilation.emitAsset(oneFilename, oneSource);
67 |
68 | const twoSource = new RawSource(twoHTMLContent);
69 |
70 | compilation.emitAsset(twoFilename, twoSource);
71 | }
72 | );
73 | });
74 | }
75 | }
76 | ]
77 | };
78 |
--------------------------------------------------------------------------------
/tests/fixtures/lazy-compilation-single-entry/entry.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/lazy-compilation-single-entry/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLContent = `
4 |
5 |
6 |
7 |
8 | test
9 |
10 |
11 |
12 |
13 | `;
14 |
15 | module.exports = {
16 | devtool: false,
17 | mode: "development",
18 | context: __dirname,
19 | stats: "none",
20 | entry: "./entry.js",
21 | output: {
22 | path: "/"
23 | },
24 | experiments: {
25 | lazyCompilation: true
26 | },
27 | infrastructureLogging: {
28 | level: "info",
29 | stream: {
30 | write: () => {}
31 | }
32 | },
33 | plugins: [
34 | {
35 | apply(compiler) {
36 | const pluginName = "html-generator-plugin-test";
37 | const filename = "test.html";
38 |
39 | compiler.hooks.thisCompilation.tap(pluginName, compilation => {
40 | const { RawSource } = compiler.webpack.sources;
41 |
42 | compilation.hooks.processAssets.tap(
43 | {
44 | name: pluginName,
45 | stage:
46 | compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
47 | },
48 | () => {
49 | const source = new RawSource(HTMLContent);
50 |
51 | compilation.emitAsset(filename, source);
52 | }
53 | );
54 | });
55 | }
56 | }
57 | ]
58 | };
59 |
--------------------------------------------------------------------------------
/tests/fixtures/mime-types-config/file.custom:
--------------------------------------------------------------------------------
1 | test
2 |
--------------------------------------------------------------------------------
/tests/fixtures/mime-types-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("./file.custom");
4 |
5 | console.log("Hey.");
6 |
--------------------------------------------------------------------------------
/tests/fixtures/mime-types-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const moduleRuleForCustom = {
4 | test: /\.custom$/,
5 | type: "asset/resource",
6 | generator: {
7 | filename: "[name][ext]"
8 | }
9 | };
10 |
11 | module.exports = {
12 | mode: "development",
13 | context: __dirname,
14 | stats: "none",
15 | entry: "./foo.js",
16 | output: {
17 | path: "/"
18 | },
19 | node: false,
20 | infrastructureLogging: {
21 | level: "warn"
22 | },
23 | module: {
24 | rules: [
25 | {
26 | ...moduleRuleForCustom
27 | }
28 | ]
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/tests/fixtures/module-federation-config/entry1.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = "entry1";
4 |
--------------------------------------------------------------------------------
/tests/fixtures/module-federation-config/entry2.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = "entry2";
4 |
--------------------------------------------------------------------------------
/tests/fixtures/module-federation-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | mode: "development",
5 | target: "node",
6 | stats: "none",
7 | context: __dirname,
8 | entry: ["./entry1.js", "./entry2.js"],
9 | output: {
10 | path: "/",
11 | libraryTarget: "umd"
12 | },
13 | infrastructureLogging: {
14 | level: "warn"
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/tests/fixtures/module-federation-config/webpack.multi.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = [
4 | {
5 | mode: "development",
6 | target: "node",
7 | context: __dirname,
8 | stats: "none",
9 | entry: ["./entry1.js", "./entry2.js"],
10 | output: {
11 | path: "/",
12 | libraryTarget: "umd"
13 | },
14 | infrastructureLogging: {
15 | level: "warn"
16 | }
17 | }
18 | ];
19 |
--------------------------------------------------------------------------------
/tests/fixtures/module-federation-config/webpack.object-entry.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | mode: "development",
5 | target: "node",
6 | stats: "none",
7 | context: __dirname,
8 | entry: {
9 | foo: "./entry1.js",
10 | main: ["./entry1.js", "./entry2.js"]
11 | },
12 | output: {
13 | path: "/",
14 | libraryTarget: "umd"
15 | },
16 | infrastructureLogging: {
17 | level: "warn"
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/tests/fixtures/module-federation-config/webpack.plugin.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const ModuleFederationPlugin =
4 | require("@rspack/core").container.ModuleFederationPlugin;
5 |
6 | module.exports = {
7 | mode: "development",
8 | target: "node",
9 | stats: "none",
10 | context: __dirname,
11 | entry: ["./entry1.js"],
12 | plugins: [
13 | new ModuleFederationPlugin({
14 | name: "app1",
15 | library: { type: "var", name: "app1" },
16 | filename: "remoteEntry.js",
17 | exposes: {
18 | "./entry1": "./entry1"
19 | }
20 | })
21 | ],
22 | infrastructureLogging: {
23 | level: "warn"
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-compiler-one-configuration/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-compiler-one-configuration/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = [
6 | {
7 | target: "web",
8 | mode: "development",
9 | context: __dirname,
10 | stats: "none",
11 | entry: "./foo.js",
12 | output: {
13 | path: "/"
14 | },
15 | node: false,
16 | infrastructureLogging: {
17 | level: "info",
18 | stream: {
19 | write: () => {}
20 | }
21 | },
22 | plugins: [new HTMLGeneratorPlugin()]
23 | }
24 | ];
25 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-compiler-two-configurations/one.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("one");
4 | // comment
5 | // comment
--------------------------------------------------------------------------------
/tests/fixtures/multi-compiler-two-configurations/two.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("two");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-compiler-two-configurations/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = [
6 | {
7 | target: "web",
8 | name: "one",
9 | mode: "development",
10 | context: __dirname,
11 | entry: "./one.js",
12 | stats: "none",
13 | output: {
14 | path: "/",
15 | filename: "one-[name].js"
16 | },
17 | plugins: [new HTMLGeneratorPlugin()],
18 | infrastructureLogging: {
19 | level: "info",
20 | stream: {
21 | write: () => {}
22 | }
23 | }
24 | },
25 | {
26 | target: "web",
27 | name: "two",
28 | mode: "development",
29 | context: __dirname,
30 | entry: "./two.js",
31 | stats: "none",
32 | output: {
33 | path: "/",
34 | filename: "two-[name].js"
35 | },
36 | plugins: [new HTMLGeneratorPlugin()],
37 | infrastructureLogging: {
38 | level: "info",
39 | stream: {
40 | write: () => {}
41 | }
42 | }
43 | }
44 | ];
45 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-public-path-config/bar.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-public-path-config/baz.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-public-path-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("./test.html");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-public-path-config/test.html:
--------------------------------------------------------------------------------
1 | hello
2 |
--------------------------------------------------------------------------------
/tests/fixtures/multi-public-path-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const path = require("path");
4 |
5 | const moduleRuleForHTML = {
6 | test: /\.html$/,
7 | type: "asset/resource",
8 | generator: {
9 | filename: "path/to/file.html"
10 | }
11 | };
12 |
13 | module.exports = [
14 | {
15 | mode: "development",
16 | context: __dirname,
17 | stats: "none",
18 | entry: "./foo.js",
19 | output: {
20 | path: __dirname,
21 | filename: "foo.js",
22 | publicPath: "/bundle1/"
23 | },
24 | infrastructureLogging: {
25 | level: "warn"
26 | },
27 | module: {
28 | rules: [
29 | {
30 | ...moduleRuleForHTML
31 | }
32 | ]
33 | }
34 | },
35 | {
36 | mode: "development",
37 | context: __dirname,
38 | stats: "none",
39 | entry: "./bar.js",
40 | output: {
41 | path: path.join(__dirname, "named"),
42 | filename: "bar.js",
43 | publicPath: "/bundle2/"
44 | },
45 | name: "named",
46 | infrastructureLogging: {
47 | level: "warn"
48 | }
49 | },
50 | {
51 | mode: "development",
52 | context: __dirname,
53 | entry: "./bar.js",
54 | output: {
55 | path: path.join(__dirname, "dist"),
56 | filename: "bar.js",
57 | publicPath: "auto"
58 | },
59 | name: "other",
60 | stats: false
61 | }
62 | ];
63 |
--------------------------------------------------------------------------------
/tests/fixtures/overlay-config/foo.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/overlay-config/foo.js
--------------------------------------------------------------------------------
/tests/fixtures/overlay-config/trusted-types.webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/trusted-types-html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/",
12 | trustedTypes: { policyName: "webpack" }
13 | },
14 | infrastructureLogging: {
15 | level: "info",
16 | stream: {
17 | write: () => {}
18 | }
19 | },
20 | plugins: [new HTMLGeneratorPlugin()]
21 | };
22 |
--------------------------------------------------------------------------------
/tests/fixtures/overlay-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/"
12 | },
13 | infrastructureLogging: {
14 | level: "info",
15 | stream: {
16 | write: () => {}
17 | }
18 | },
19 | plugins: [new HTMLGeneratorPlugin()]
20 | };
21 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-custom/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // 'npm run prepare' must be run for this to work during testing
4 | const CustomClient = require("../custom-client/CustomSockJSClient");
5 |
6 | window.expectedClient = CustomClient;
7 | // eslint-disable-next-line camelcase, no-undef
8 | window.injectedClient = __webpack_dev_server_client__;
9 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-custom/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | /**
6 | * @type {import('@rspack/core').RspackOptions}
7 | */
8 | const config = {
9 | mode: "development",
10 | context: __dirname,
11 | stats: "none",
12 | entry: "./foo.js",
13 | output: {
14 | path: "/"
15 | },
16 | node: false,
17 | infrastructureLogging: {
18 | level: "info",
19 | stream: {
20 | write: () => {}
21 | }
22 | },
23 | plugins: [new HTMLGeneratorPlugin()]
24 | };
25 |
26 | module.exports = config;
27 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-default/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // 'npm run prepare' must be run for this to work during testing
4 | const WebsocketClient =
5 | require("webpack-dev-server/client/clients/WebSocketClient").default;
6 |
7 | window.expectedClient = WebsocketClient;
8 | // eslint-disable-next-line camelcase, no-undef
9 | window.injectedClient = __webpack_dev_server_client__.default;
10 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-default/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/"
12 | },
13 | node: false,
14 | infrastructureLogging: {
15 | level: "info",
16 | stream: {
17 | write: () => {}
18 | }
19 | },
20 | plugins: [new HTMLGeneratorPlugin()]
21 | };
22 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-sockjs-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // 'npm run prepare' must be run for this to work during testing
4 | const SockJSClient =
5 | require("webpack-dev-server/client/clients/SockJSClient").default;
6 |
7 | window.expectedClient = SockJSClient;
8 | // eslint-disable-next-line camelcase, no-undef
9 | window.injectedClient = __webpack_dev_server_client__.default;
10 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-sockjs-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/"
12 | },
13 | node: false,
14 | infrastructureLogging: {
15 | level: "info",
16 | stream: {
17 | write: () => {}
18 | }
19 | },
20 | plugins: [new HTMLGeneratorPlugin()]
21 | };
22 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-ws-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // 'npm run prepare' must be run for this to work during testing
4 | const WebsocketClient =
5 | require("webpack-dev-server/client/clients/WebSocketClient").default;
6 |
7 | window.expectedClient = WebsocketClient;
8 | // eslint-disable-next-line camelcase, no-undef
9 | window.injectedClient = __webpack_dev_server_client__.default;
10 |
--------------------------------------------------------------------------------
/tests/fixtures/provide-plugin-ws-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/"
12 | },
13 | node: false,
14 | infrastructureLogging: {
15 | level: "info",
16 | stream: {
17 | write: () => {}
18 | }
19 | },
20 | plugins: [new HTMLGeneratorPlugin()]
21 | };
22 |
--------------------------------------------------------------------------------
/tests/fixtures/reload-config-2/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | // eslint-disable-next-line import/no-unresolved
4 | require("./main.css");
5 |
--------------------------------------------------------------------------------
/tests/fixtures/reload-config-2/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/"
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.css$/,
17 | use: [{ loader: "style-loader" }, { loader: "css-loader" }]
18 | }
19 | ]
20 | },
21 | node: false,
22 | infrastructureLogging: {
23 | level: "info",
24 | stream: {
25 | write: () => {}
26 | }
27 | },
28 | plugins: [new HTMLGeneratorPlugin()]
29 | };
30 |
--------------------------------------------------------------------------------
/tests/fixtures/reload-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | require("./main.css");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/reload-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | entry: "./foo.js",
9 | stats: "none",
10 | output: {
11 | path: "/"
12 | },
13 | module: {
14 | rules: [
15 | {
16 | test: /\.css$/,
17 | use: [{ loader: "style-loader" }, { loader: "css-loader" }]
18 | }
19 | ]
20 | },
21 | infrastructureLogging: {
22 | level: "info",
23 | stream: {
24 | write: () => {}
25 | }
26 | },
27 | plugins: [new HTMLGeneratorPlugin()]
28 | };
29 |
--------------------------------------------------------------------------------
/tests/fixtures/simple-config-other/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log(
4 | "Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Long Line."
5 | );
6 |
--------------------------------------------------------------------------------
/tests/fixtures/simple-config-other/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | mode: "development",
5 | context: __dirname,
6 | stats: "none",
7 | entry: "./foo.js",
8 | output: {
9 | path: "/"
10 | },
11 | node: false,
12 | infrastructureLogging: {
13 | level: "warn"
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/tests/fixtures/simple-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/simple-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | path: "/"
12 | },
13 | node: false,
14 | infrastructureLogging: {
15 | level: "info",
16 | stream: {
17 | write: () => {}
18 | }
19 | },
20 | plugins: [new HTMLGeneratorPlugin()]
21 | };
22 |
--------------------------------------------------------------------------------
/tests/fixtures/ssl/localhost-cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDCTCCAfGgAwIBAgIUevWiuCfenWuq9KyC8aQ/tc1Io14wDQYJKoZIhvcNAQEL
3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDQyNDE2MDYyMloXDTI0MDUy
4 | NDE2MDYyMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
5 | AAOCAQ8AMIIBCgKCAQEA1v/lb9u9WkqkF7zjIKe2R+b4S0sQnWIfBFZ0ggtaOL0a
6 | ntud/EuaGQgLtJgSwO2M2xIqKx+yoLhoM+273EJe0KmfJMxYNAkhwP9h6vrKnaQJ
7 | mpAhoalfEGyCrnHHMKISAAn4Rlc8NXnULoFhHzNm8bdqvP33rCmsJ+tNYC5kwzyt
8 | HvRNFyg9BOUfACiPW17opFH0rao3IfZrQ6yRbknef1pX1x2pbDAH14rCT/vXaTs6
9 | VGuqLE/wRsSt+7nMHy/PmXxMyb4G4/UflYtnKfmXpDRw+TDEGzvTZedtoOz+rrJC
10 | e989R9qYGrlPfyfZbI+O348FV66I+jcD+/EUQs+HkwIDAQABo1MwUTAdBgNVHQ4E
11 | FgQU6bk4LSwtVQEt7V/ev+Zj270zdAkwHwYDVR0jBBgwFoAU6bk4LSwtVQEt7V/e
12 | v+Zj270zdAkwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAUBgo
13 | E3CZrrc/MaadFg1meNk+eKACmTsIa5cT6zi7MsvoKakXEd4bGd+iLifUzlAa1ygj
14 | dQppfprb5t68I7oO9/lkh2DfKrXxW/RpdhB05KslUd8q/3XY5kyao5quzeiVoMHR
15 | u+XYjoy2mTwdUC2uzFy6rkHsAkJy2vJJoDdlNsrKn6AZmh+voHHKrAtOL4gnanQV
16 | wR1u8eBVfk2MKIl2pNSCA4bD16uZyp3+oqq097BEoVa1pR+l8nwbsh/YfALifq/d
17 | P3yiN5+EqgiOIF9b8PZORe+Ry1O7uvPnU2ZRkVWPJ1S17Ms0lnr7IY3qjSBTuK66
18 | 5uYi7ojrb5Vf0UL5oQ==
19 | -----END CERTIFICATE-----
20 |
--------------------------------------------------------------------------------
/tests/fixtures/ssl/localhost-privkey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQDW/+Vv271aSqQX
3 | vOMgp7ZH5vhLSxCdYh8EVnSCC1o4vRqe2538S5oZCAu0mBLA7YzbEiorH7KguGgz
4 | 7bvcQl7QqZ8kzFg0CSHA/2Hq+sqdpAmakCGhqV8QbIKucccwohIACfhGVzw1edQu
5 | gWEfM2bxt2q8/fesKawn601gLmTDPK0e9E0XKD0E5R8AKI9bXuikUfStqjch9mtD
6 | rJFuSd5/WlfXHalsMAfXisJP+9dpOzpUa6osT/BGxK37ucwfL8+ZfEzJvgbj9R+V
7 | i2cp+ZekNHD5MMQbO9Nl522g7P6uskJ73z1H2pgauU9/J9lsj47fjwVXroj6NwP7
8 | 8RRCz4eTAgMBAAECggEAA+zbFv43iEj5kvdfXC7DrK9iVBmUPZNXhqA/c0paxNNr
9 | A4B182+76f4UHKF0IjKUEkHUJEJpY/bJ7DzIY76QdZXLMoRKjfSmuZvQAVa/0T33
10 | 8Or1ujpZ4nZgsmegX9ptorOL5VjdYAqP3aN+DvBEzl/vYnDujyWZn4bzvDBMpaXS
11 | 39qW1MkcZ8UiP1fRad76+S57WnieBV+NRHYEAiDdMFKXLuw/igX/xOSZgq5Jh3I2
12 | hLS49S41dN1P9l9H2bPMw0CthNvMPPaemwKHz+84hSS+P4VJOWJzlGnXEdIFuqBR
13 | GFBESQzcemfS9DDB22Yt06YujBCbwTVVAxj73lnKkQKBgQDvYXK36J9y/NphDAWi
14 | Cwti5oE3eSfV0YazQwm+rRwC64wbpBFAm9ujwjUmaYBg75lBLF5nOOe8s1n95g5I
15 | tLfFb+zuZh8NNLjhfNE9/SNmRnnMvbcaDHeIE2RMAz+PuLN/gFLmsVIwK2X1LRC2
16 | 0vHjw9Yzh6JLiOajAchzhZiCEQKBgQDl7R6Wfggo8myETA8Uv5tWot3IcquRkEl/
17 | TRCyao2/79rAGexS7piwD7FPdSDOk1zfZFYUOMzyMjj60sGcPRPqRX6D0usEODLQ
18 | TwsTJSCNgPnIOkqKkccwtqlTimbRIrPUSQfFPj56RzKKWdrJ/P3LPRjzkK7i3vLV
19 | EGlAENaLYwKBgHKSOnzpWr+HY+IFBgErthRs7LWnSDifYxATauuXIQwIvvNP0G4S
20 | 6snzHss2vZonszstSDWxV8DKOq052eZUkIxv6H+l4wDIFiDeQ6uep73Ax3UF7EgM
21 | ZX18gombGGXqagcBXSxK/GJPsynomtJWHi38Ql5BcZ0jdffY157q9zZxAoGAPZtD
22 | Tt+GIDKUkP4wLEcKwDPzaPoQrngSuWFUz/ls8bi6zC4l/DKiBsqtn7Sqja8+ezzP
23 | M6vkfiCm084UwmA7LdJhC8E/52mHc/k55m9UQZYFV3kG8AoPbSYESLYUxoSd2ouW
24 | 4WrEIs9g42EgFm8LMaG1Rc3GjlNejWhQSzI3yjECf3v7VoAcUwVfuVkwbm9W24vR
25 | neFTF8QBl//fxIdxZwoj5SrSgMOjmZ3pXA/ZbFJ0pB4Rh5dmKTYqdpfXsOTiBuwB
26 | XlqPVpN8UZEl3edpufLDyPldNej/9kEAkK5FS3YVyIQEg75739bCTlfzzCX1HdMx
27 | q98XYm/n5LWYFezsAt0=
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/other/foo.html:
--------------------------------------------------------------------------------
1 | Foo!
2 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/assets/example.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/static-config/public/assets/example.txt
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/assets/other.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/static-config/public/assets/other.txt
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/bar/index.html:
--------------------------------------------------------------------------------
1 | Heyo
2 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/foo.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/static-config/public/foo.wasm
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/index.html:
--------------------------------------------------------------------------------
1 | Heyo.
2 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/node_modules/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/static-config/public/node_modules/.gitkeep
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/node_modules/index.html:
--------------------------------------------------------------------------------
1 | bar
--------------------------------------------------------------------------------
/tests/fixtures/static-config/public/other.html:
--------------------------------------------------------------------------------
1 | Other html
2 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/static/index.html:
--------------------------------------------------------------------------------
1 | Heyo.
2 |
--------------------------------------------------------------------------------
/tests/fixtures/static-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | mode: "development",
5 | context: __dirname,
6 | stats: "none",
7 | entry: "./foo.js",
8 | output: {
9 | publicPath: "/"
10 | },
11 | infrastructureLogging: {
12 | level: "warn"
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/tests/fixtures/universal-compiler-config/browser.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hello from the browser");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/universal-compiler-config/server.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hello from the server");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/universal-compiler-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = [
6 | {
7 | name: "browser",
8 | mode: "development",
9 | context: __dirname,
10 | stats: "none",
11 | entry: "./browser.js",
12 | output: {
13 | path: "/",
14 | filename: "browser.js"
15 | },
16 | plugins: [new HTMLGeneratorPlugin()],
17 | infrastructureLogging: {
18 | level: "info",
19 | stream: {
20 | write: () => {}
21 | }
22 | }
23 | },
24 | {
25 | name: "server",
26 | mode: "development",
27 | context: __dirname,
28 | target: "node",
29 | stats: "none",
30 | entry: "./server.js",
31 | output: {
32 | path: "/",
33 | filename: "server.js"
34 | },
35 | plugins: [new HTMLGeneratorPlugin()],
36 | infrastructureLogging: {
37 | level: "info",
38 | stream: {
39 | write: () => {}
40 | }
41 | }
42 | }
43 | ];
44 |
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/foo.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | console.log("Hey.");
4 |
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/other/foo.html:
--------------------------------------------------------------------------------
1 | Foo!
2 |
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/public/assets/example.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/watch-files-config/public/assets/example.txt
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/public/assets/non-exist.txt:
--------------------------------------------------------------------------------
1 | Kurosaki Ichigo
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/public/assets/other.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/fixtures/watch-files-config/public/assets/other.txt
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/public/bar/index.html:
--------------------------------------------------------------------------------
1 | Heyo
2 |
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/public/other.html:
--------------------------------------------------------------------------------
1 | Other html
2 |
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/static/index.html:
--------------------------------------------------------------------------------
1 | Heyo.
2 |
--------------------------------------------------------------------------------
/tests/fixtures/watch-files-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
4 |
5 | module.exports = {
6 | mode: "development",
7 | context: __dirname,
8 | stats: "none",
9 | entry: "./foo.js",
10 | output: {
11 | publicPath: "/"
12 | },
13 | infrastructureLogging: {
14 | level: "warn"
15 | },
16 | plugins: [new HTMLGeneratorPlugin()]
17 | };
18 |
--------------------------------------------------------------------------------
/tests/fixtures/worker-config-dev-server-false/index.js:
--------------------------------------------------------------------------------
1 | const myWorker = new Worker("./worker-bundle.js");
2 |
3 | myWorker.onmessage = (event) => {
4 | console.log(`Worker said: ${event.data}`);
5 | };
6 |
7 | myWorker.postMessage("message");
8 |
--------------------------------------------------------------------------------
/tests/fixtures/worker-config-dev-server-false/public/worker-bundle.js:
--------------------------------------------------------------------------------
1 | (() => { // webpackBootstrap
2 | var __webpack_modules__ = ({});
3 | /************************************************************************/
4 | // The module cache
5 | var __webpack_module_cache__ = {};
6 |
7 | // The require function
8 | function __webpack_require__(moduleId) {
9 |
10 | // Check if module is in cache
11 | var cachedModule = __webpack_module_cache__[moduleId];
12 | if (cachedModule !== undefined) {
13 | return cachedModule.exports;
14 | }
15 | // Create a new module (and put it into the cache)
16 | var module = (__webpack_module_cache__[moduleId] = {
17 | exports: {}
18 | });
19 | // Execute the module function
20 | __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
21 |
22 | // Return the exports of the module
23 | return module.exports;
24 |
25 | }
26 |
27 | /************************************************************************/
28 | // webpack/runtime/rspack_version
29 | (() => {
30 | __webpack_require__.rv = () => ("1.3.11")
31 | })();
32 | // webpack/runtime/rspack_unique_id
33 | (() => {
34 | __webpack_require__.ruid = "bundler=rspack@1.3.11";
35 |
36 | })();
37 | /************************************************************************/
38 |
39 | /*!*******************!*\
40 | !*** ./worker.js ***!
41 | \*******************/
42 | postMessage("I'm working before postMessage");
43 |
44 | onmessage = (event) => {
45 | postMessage(`Message sent: ${event.data}`);
46 | };
47 |
48 | })()
49 | ;
--------------------------------------------------------------------------------
/tests/fixtures/worker-config-dev-server-false/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
3 |
4 | module.exports = [
5 | {
6 | name: "app",
7 | // dependencies: ["worker"],
8 | devtool: false,
9 | target: "web",
10 | entry: "./index.js",
11 | mode: "development",
12 | context: __dirname,
13 | stats: "none",
14 | output: {
15 | path: path.resolve(__dirname, "./dist/"),
16 | },
17 | infrastructureLogging: {
18 | level: "info",
19 | stream: {
20 | write: () => {},
21 | },
22 | },
23 | plugins: [new HTMLGeneratorPlugin()],
24 | },
25 | {
26 | name: "worker",
27 | devtool: false,
28 | target: "webworker",
29 | entry: "./worker.js",
30 | mode: "development",
31 | context: __dirname,
32 | stats: "none",
33 | output: {
34 | path: path.resolve(__dirname, "public"),
35 | filename: "worker-bundle.js",
36 | },
37 | infrastructureLogging: {
38 | level: "info",
39 | stream: {
40 | write: () => {},
41 | },
42 | },
43 | devServer: false,
44 | },
45 | ];
46 |
--------------------------------------------------------------------------------
/tests/fixtures/worker-config-dev-server-false/worker.js:
--------------------------------------------------------------------------------
1 | postMessage("I'm working before postMessage");
2 |
3 | onmessage = (event) => {
4 | postMessage(`Message sent: ${event.data}`);
5 | };
6 |
--------------------------------------------------------------------------------
/tests/fixtures/worker-config/index.js:
--------------------------------------------------------------------------------
1 | const myWorker = new Worker("./worker.js");
2 |
3 | myWorker.onmessage = (event) => {
4 | console.log(`Worker said: ${event.data}`);
5 | };
6 |
7 | myWorker.postMessage("message");
8 |
--------------------------------------------------------------------------------
/tests/fixtures/worker-config/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HTMLGeneratorPlugin = require("../../helpers/html-generator-plugin");
2 |
3 | module.exports = [
4 | {
5 | name: "app",
6 | dependencies: ["worker"],
7 | devtool: false,
8 | target: "web",
9 | entry: "./index.js",
10 | mode: "development",
11 | context: __dirname,
12 | stats: "none",
13 | output: {
14 | path: "/",
15 | },
16 | infrastructureLogging: {
17 | level: "info",
18 | stream: {
19 | write: () => {},
20 | },
21 | },
22 | plugins: [new HTMLGeneratorPlugin()],
23 | },
24 | {
25 | name: "worker",
26 | devtool: false,
27 | target: "webworker",
28 | entry: "./worker.js",
29 | mode: "development",
30 | context: __dirname,
31 | stats: "none",
32 | output: {
33 | path: "/",
34 | filename: "worker.js",
35 | },
36 | infrastructureLogging: {
37 | level: "info",
38 | stream: {
39 | write: () => {},
40 | },
41 | },
42 | },
43 | ];
44 |
--------------------------------------------------------------------------------
/tests/fixtures/worker-config/worker.js:
--------------------------------------------------------------------------------
1 | postMessage("I'm working before postMessage");
2 |
3 | onmessage = (event) => {
4 | postMessage(`Message sent: ${event.data}`);
5 | };
6 |
--------------------------------------------------------------------------------
/tests/helpers/conditional-test.js:
--------------------------------------------------------------------------------
1 | const isWindows = process.platform === "win32";
2 |
3 | function skipTestOnWindows(reason) {
4 | if (isWindows) {
5 | test.skip(reason, () => {});
6 | }
7 | return isWindows;
8 | }
9 |
10 | module.exports.skipTestOnWindows = skipTestOnWindows;
11 |
--------------------------------------------------------------------------------
/tests/helpers/custom-http.js:
--------------------------------------------------------------------------------
1 | const customHTTP = require("node:http");
2 |
3 | module.exports = customHTTP;
4 |
--------------------------------------------------------------------------------
/tests/helpers/get-port.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Based on the packages get-port https://www.npmjs.com/package/get-port
3 | * and portfinder https://www.npmjs.com/package/portfinder
4 | * The code structure is similar to get-port, but it searches
5 | * ports deterministically like portfinder
6 | */
7 | const net = require("node:net");
8 | const os = require("node:os");
9 |
10 | const minPort = 1024;
11 | const maxPort = 65_535;
12 |
13 | /**
14 | * @return {Set}
15 | */
16 | const getLocalHosts = () => {
17 | const interfaces = os.networkInterfaces();
18 |
19 | // Add undefined value for createServer function to use default host,
20 | // and default IPv4 host in case createServer defaults to IPv6.
21 | // eslint-disable-next-line no-undefined
22 | const results = new Set([undefined, "0.0.0.0"]);
23 |
24 | for (const _interface of Object.values(interfaces)) {
25 | if (_interface) {
26 | for (const config of _interface) {
27 | results.add(config.address);
28 | }
29 | }
30 | }
31 |
32 | return results;
33 | };
34 |
35 | /**
36 | * @param {number} basePort
37 | * @param {string | undefined} host
38 | * @return {Promise}
39 | */
40 | const checkAvailablePort = (basePort, host) =>
41 | new Promise((resolve, reject) => {
42 | const server = net.createServer();
43 | server.unref();
44 | server.on("error", reject);
45 |
46 | server.listen(basePort, host, () => {
47 | // Next line should return AddressInfo because we're calling it after listen() and before close()
48 | const { port } = /** @type {import("net").AddressInfo} */ (
49 | server.address()
50 | );
51 | server.close(() => {
52 | resolve(port);
53 | });
54 | });
55 | });
56 |
57 | /**
58 | * @param {number} port
59 | * @param {Set} hosts
60 | * @return {Promise}
61 | */
62 | const getAvailablePort = async (port, hosts) => {
63 | /**
64 | * Errors that mean that host is not available.
65 | * @type {Set}
66 | */
67 | const nonExistentInterfaceErrors = new Set(["EADDRNOTAVAIL", "EINVAL"]);
68 | /* Check if the post is available on every local host name */
69 | for (const host of hosts) {
70 | try {
71 | await checkAvailablePort(port, host); // eslint-disable-line no-await-in-loop
72 | } catch (error) {
73 | /* We throw an error only if the interface exists */
74 | if (
75 | !nonExistentInterfaceErrors.has(
76 | /** @type {NodeJS.ErrnoException} */ (error).code,
77 | )
78 | ) {
79 | throw error;
80 | }
81 | }
82 | }
83 |
84 | return port;
85 | };
86 |
87 | /**
88 | * @param {number} basePort
89 | * @param {string=} host
90 | * @return {Promise}
91 | */
92 | async function getPorts(basePort, host) {
93 | if (basePort < minPort || basePort > maxPort) {
94 | throw new Error(`Port number must lie between ${minPort} and ${maxPort}`);
95 | }
96 |
97 | let port = basePort;
98 | const localhosts = getLocalHosts();
99 | let hosts;
100 | if (host && !localhosts.has(host)) {
101 | hosts = new Set([host]);
102 | } else {
103 | /* If the host is equivalent to localhost
104 | we need to check every equivalent host
105 | else the port might falsely appear as available
106 | on some operating systems */
107 | hosts = localhosts;
108 | }
109 | /** @type {Set} */
110 | const portUnavailableErrors = new Set(["EADDRINUSE", "EACCES"]);
111 | while (port <= maxPort) {
112 | try {
113 | const availablePort = await getAvailablePort(port, hosts); // eslint-disable-line no-await-in-loop
114 | return availablePort;
115 | } catch (error) {
116 | /* Try next port if port is busy; throw for any other error */
117 | if (
118 | !portUnavailableErrors.has(
119 | /** @type {NodeJS.ErrnoException} */ (error).code,
120 | )
121 | ) {
122 | throw error;
123 | }
124 | port += 1;
125 | }
126 | }
127 |
128 | throw new Error("No available ports found");
129 | }
130 |
131 | module.exports = getPorts;
132 |
--------------------------------------------------------------------------------
/tests/helpers/global-setup-test.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-extraneous-dependencies
2 | const tcpPortUsed = require("tcp-port-used");
3 | const { webpackVersion } = require("@rspack/core/package.json");
4 | const ports = require("./ports-map");
5 |
6 | // eslint-disable-next-line no-console
7 | console.log(`\n Running tests for webpack @${webpackVersion} \n`);
8 |
9 | async function validatePorts() {
10 | const samples = [];
11 |
12 | for (const key of Object.keys(ports)) {
13 | const value = ports[key];
14 | const arr = Array.isArray(value) ? value : [value];
15 |
16 | for (const port of arr) {
17 | const check = tcpPortUsed.check(port, "localhost").then((inUse) => {
18 | if (inUse) {
19 | throw new Error(`${port} has already used. [${key}]`);
20 | }
21 | });
22 |
23 | samples.push(check);
24 | }
25 | }
26 |
27 | try {
28 | await Promise.all(samples);
29 | } catch (e) {
30 | // eslint-disable-next-line no-console
31 | console.error(e);
32 | process.exit(1);
33 | }
34 | }
35 |
36 | module.exports = validatePorts;
37 |
--------------------------------------------------------------------------------
/tests/helpers/html-generator-plugin.js:
--------------------------------------------------------------------------------
1 | const HTMLContentForIndex = `
2 |
3 |
4 |
5 |
6 | webpack-dev-server
7 |
8 |
9 | webpack-dev-server is running...
10 |
11 |
12 |
13 | `;
14 |
15 | const HTMLContentForAssets = (assetName) => `
16 |
17 |
18 |
19 |
20 | webpack-dev-server
21 |
22 |
23 | (${assetName}>)webpack-dev-server is running...
24 |
25 |
26 |
27 | `;
28 |
29 | const HTMLContentForTest = `
30 |
31 |
32 |
33 |
34 | test
35 |
36 |
37 | Created via HTMLGeneratorPlugin
38 |
39 |
40 | `;
41 |
42 | module.exports = class HTMLGeneratorPlugin {
43 | // eslint-disable-next-line class-methods-use-this
44 | apply(compiler) {
45 | const pluginName = "html-generator-plugin";
46 |
47 | compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
48 | const { RawSource } = compiler.webpack.sources;
49 |
50 | compilation.hooks.processAssets.tap(
51 | {
52 | name: pluginName,
53 | stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
54 | },
55 | () => {
56 | const indexSource = new RawSource(HTMLContentForIndex);
57 | const testSource = new RawSource(HTMLContentForTest);
58 | const assets = compilation.getAssets();
59 |
60 | compilation.emitAsset("index.html", indexSource);
61 | compilation.emitAsset("test.html", testSource);
62 |
63 | for (const asset of assets) {
64 | const assetName = asset.name;
65 |
66 | if (assetName !== "main.js" && assetName.endsWith(".js")) {
67 | const assetSource = new RawSource(
68 | HTMLContentForAssets(assetName),
69 | );
70 | compilation.emitAsset(
71 | assetName.replace(".js", ".html"),
72 | assetSource,
73 | );
74 | }
75 | }
76 | },
77 | );
78 | });
79 | }
80 | };
81 |
--------------------------------------------------------------------------------
/tests/helpers/normalize-options.js:
--------------------------------------------------------------------------------
1 | function normalizeOptions(options) {
2 | const normalizedOptions = {};
3 |
4 | // eslint-disable-next-line guard-for-in
5 | for (const propertyName in options) {
6 | let value = options[propertyName];
7 |
8 | if (Array.isArray(value)) {
9 | value = value.map((item) => {
10 | if (Buffer.isBuffer(item)) {
11 | return "";
12 | }
13 | if (typeof item.pem !== "undefined" && Buffer.isBuffer(item.pem)) {
14 | item.pem = "";
15 | } else if (
16 | typeof item.buf !== "undefined" &&
17 | Buffer.isBuffer(item.buf)
18 | ) {
19 | item.buf = "";
20 | }
21 |
22 | return item;
23 | });
24 | } else if (Buffer.isBuffer(value)) {
25 | value = "";
26 | }
27 |
28 | normalizedOptions[propertyName] = value;
29 | }
30 |
31 | return normalizedOptions;
32 | }
33 |
34 | module.exports = normalizeOptions;
35 |
--------------------------------------------------------------------------------
/tests/helpers/normalize.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 |
3 | const CURRENT_CWD = process.cwd();
4 | const ROOT = path.resolve(__dirname, "../../");
5 |
6 | const CSS_LOADER = path.dirname(require.resolve("css-loader"));
7 | const RELATIVE_CSS_LOADER = path.relative(
8 | path.dirname(
9 | path.resolve(__dirname, "../fixtures/reload-config/webpack.config"),
10 | ),
11 | CSS_LOADER,
12 | );
13 | const RSPACK = path.dirname(require.resolve("@rspack/core/package.json"));
14 |
15 | const rspack = require("@rspack/core");
16 | const RSPACK_MODULE = require.cache[require.resolve("@rspack/core")];
17 | const TAPABLE = path.dirname(
18 | RSPACK_MODULE.require.resolve("@rspack/lite-tapable"),
19 | );
20 |
21 | const normalize = (str) => {
22 | let normalizedStr = str.replace(/(\\)+/g, "/");
23 |
24 | normalizedStr = normalizedStr
25 | .split(RSPACK.replace(/(\\)+/g, "/"))
26 | .join("");
27 |
28 | normalizedStr = normalizedStr
29 | .split(CSS_LOADER.replace(/(\\)+/g, "/"))
30 | .join("");
31 |
32 | normalizedStr = normalizedStr
33 | .split(RELATIVE_CSS_LOADER.replace(/(\\)+/g, "/"))
34 | .join("");
35 |
36 | normalizedStr = normalizedStr
37 | .split(RELATIVE_CSS_LOADER.replace(/(\\)+/g, "/"))
38 | .join("");
39 |
40 | normalizedStr = normalizedStr
41 | .split(TAPABLE.replace(/(\\)+/g, "/"))
42 | .join("");
43 |
44 | normalizedStr = normalizedStr
45 | .split(ROOT.replace(/(\\)+/g, "/"))
46 | .join("");
47 |
48 | normalizedStr = normalizedStr
49 | .split(CURRENT_CWD.replace(/(\\)+/g, "/"))
50 | .join("");
51 |
52 | normalizedStr = normalizedStr.replace(/:\d+:\d+/g, "::");
53 | normalizedStr = normalizedStr.replace(
54 | /@@ -\d+,\d+ \+\d+,\d+ @@/g,
55 | "@@ ... @@",
56 | );
57 | return normalizedStr;
58 | };
59 |
60 | expect.addSnapshotSerializer({
61 | test(value) {
62 | return typeof value === "string";
63 | },
64 | print(received) {
65 | return normalize(received);
66 | },
67 | });
68 |
--------------------------------------------------------------------------------
/tests/helpers/ports-map.js:
--------------------------------------------------------------------------------
1 | // important: new port mappings must be added to the bottom of this list
2 | const listOfTests = {
3 | // CLI tests
4 | "cli-basic": 1,
5 | "cli-port-option": 1,
6 | // e2e tests
7 | bundle: 1,
8 | "sockjs-client": 1,
9 | "web-socket-client": 1,
10 | "hot-and-live-reload": 1,
11 | logging: 1,
12 | overlay: 1,
13 | progress: 1,
14 | "server-and-client-transport": 1,
15 | "web-socket-server-url": 2,
16 | // integration tests
17 | "module-federation": 1,
18 | "multi-compiler": 1,
19 | // unit tests
20 | bonjour: 1,
21 | "client-option": 1,
22 | "compress-option": 1,
23 | "headers-option": 1,
24 | "history-api-fallback-option": 1,
25 | "host-option": 1,
26 | "hot-option": 1,
27 | "http2-option": 1,
28 | "https-option": 1,
29 | "mime-types-option": 1,
30 | "magic-html-option": 1,
31 | "on-after-setup-middleware-option": 1,
32 | "on-before-setup-middleware-option": 1,
33 | "on-listening-option": 1,
34 | "open-option": 1,
35 | "port-option": 1,
36 | "proxy-option": 4,
37 | server: 1,
38 | "setup-exit-signals-option": 1,
39 | "static-directory-option": 1,
40 | "static-public-path-option": 1,
41 | "stats-option": 1,
42 | "watch-files-option": 1,
43 | "web-socket-server-option": 1,
44 | "sockjs-server": 1,
45 | "web-socket-server": 1,
46 | routes: 1,
47 | "web-socket-communication": 1,
48 | ipc: 1,
49 | stats: 1,
50 | "cli-allowed-hosts": 1,
51 | "cli-bonjour": 1,
52 | "cli-client": 1,
53 | "cli-colors": 1,
54 | "cli-compress": 1,
55 | "cli-history-api-fallback": 1,
56 | "cli-host": 1,
57 | "cli-hot": 1,
58 | "cli-http2": 1,
59 | "cli-https": 1,
60 | "cli-live-reload": 1,
61 | "cli-magic-html": 1,
62 | "cli-open": 1,
63 | "cli-static": 1,
64 | "cli-watch-files": 1,
65 | "cli-web-socket-server": 1,
66 | target: 1,
67 | entry: 1,
68 | "allowed-hosts": 2,
69 | host: 1,
70 | api: 1,
71 | "lazy-compilation": 1,
72 | "range-header": 1,
73 | port: 1,
74 | "web-socket-server-test": 1,
75 | "client-reconnect-option": 1,
76 | "cli-server": 1,
77 | "server-option": 1,
78 | "normalize-option": 1,
79 | "setup-middlewares-option": 1,
80 | "options-request-response": 2,
81 | app: 1,
82 | };
83 |
84 | let startPort = 8089;
85 |
86 | const ports = {};
87 |
88 | for (const key of Object.keys(listOfTests)) {
89 | const value = listOfTests[key];
90 |
91 | ports[key] =
92 | value === 1
93 | ? // biome-ignore lint/suspicious/noAssignInExpressions: _
94 | (startPort += 1)
95 | : // biome-ignore lint/suspicious/noAssignInExpressions: _
96 | [...new Array(value)].map(() => (startPort += 1));
97 | }
98 |
99 | const busy = {};
100 |
101 | module.exports = new Proxy(ports, {
102 | get(target, name) {
103 | if (!target[name]) {
104 | throw new Error(
105 | `Requested "${name}" port(s) for tests not found, please update "test/ports-map.js".`,
106 | );
107 | }
108 |
109 | if (busy[name]) {
110 | throw new Error(
111 | `The "${name}" port is already in use in another test, please add a new one.`,
112 | );
113 | }
114 |
115 | busy[name] = true;
116 |
117 | return target[name];
118 | },
119 | });
120 |
--------------------------------------------------------------------------------
/tests/helpers/puppeteer-constants.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | reloadReadyDelay: 5000,
3 | completeReloadDelay: 10000,
4 | initConsoleDelay: 3000,
5 | awaitServerCloseDelay: 1000,
6 | beforeBrowserCloseDelay: 3000,
7 | puppeteerArgs: [
8 | "--disable-background-timer-throttling",
9 | "--disable-breakpad",
10 | "--disable-client-side-phishing-detection",
11 | "--disable-cloud-import",
12 | "--disable-default-apps",
13 | "--disable-dev-shm-usage",
14 | "--disable-extensions",
15 | "--disable-gesture-typing",
16 | "--disable-hang-monitor",
17 | "--disable-infobars",
18 | "--disable-notifications",
19 | "--disable-offer-store-unmasked-wallet-cards",
20 | "--disable-offer-upload-credit-cards",
21 | "--disable-popup-blocking",
22 | "--disable-print-preview",
23 | "--disable-prompt-on-repost",
24 | "--disable-setuid-sandbox",
25 | "--disable-speech-api",
26 | "--disable-sync",
27 | "--disable-tab-for-desktop-share",
28 | "--disable-translate",
29 | "--disable-voice-input",
30 | "--disable-wake-on-wifi",
31 | "--enable-async-dns",
32 | "--enable-simple-cache-backend",
33 | "--enable-tcp-fast-open",
34 | "--enable-webgl",
35 | "--hide-scrollbars",
36 | "--ignore-gpu-blacklist",
37 | "--media-cache-size=33554432",
38 | "--metrics-recording-only",
39 | "--mute-audio",
40 | "--no-default-browser-check",
41 | "--no-first-run",
42 | "--no-pings",
43 | "--no-sandbox",
44 | "--no-zygote",
45 | "--password-store=basic",
46 | "--prerender-from-omnibox=disabled",
47 | "--use-gl=swiftshader",
48 | "--use-mock-keychain",
49 | "--disable-field-trial-config",
50 | ],
51 | };
52 |
--------------------------------------------------------------------------------
/tests/helpers/run-browser.js:
--------------------------------------------------------------------------------
1 | const puppeteer = require("puppeteer");
2 | const { puppeteerArgs } = require("./puppeteer-constants");
3 |
4 | /**
5 | * @typedef {Object} RunBrowserResult
6 | * @property {import('puppeteer').Page} page
7 | * @property {import('puppeteer').Browser} browser
8 | */
9 |
10 | /**
11 | * @param {Parameters[0]} config
12 | * @returns {Promise}
13 | */
14 | function runBrowser(config) {
15 | return new Promise((resolve, reject) => {
16 | /**
17 | * @type {import('puppeteer').Page}
18 | */
19 | let page;
20 | /**
21 | * @type {import('puppeteer').Browser}
22 | */
23 | let browser;
24 |
25 | puppeteer
26 | .launch({
27 | headless: "new",
28 | // because of invalid localhost certificate
29 | acceptInsecureCerts: true,
30 | // args come from: https://github.com/alixaxel/chrome-aws-lambda/blob/master/source/index.js
31 | args: puppeteerArgs,
32 | })
33 | .then((launchedBrowser) => {
34 | browser = launchedBrowser;
35 |
36 | return runPage(launchedBrowser, config);
37 | })
38 | .then((newPage) => {
39 | page = newPage;
40 |
41 | resolve({ page, browser });
42 | })
43 | .catch(reject);
44 | });
45 | }
46 |
47 | function runPage(browser, config) {
48 | /**
49 | * @type {import('puppeteer').Page}
50 | */
51 | let page;
52 |
53 | const options = {
54 | viewport: {
55 | width: 500,
56 | height: 500,
57 | },
58 | userAgent: "",
59 | ...config,
60 | };
61 |
62 | return Promise.resolve()
63 | .then(() => browser.newPage())
64 | .then((newPage) => {
65 | page = newPage;
66 | page.emulate(options);
67 |
68 | return page.setRequestInterception(true);
69 | })
70 | .then(() => {
71 | page.on("request", (interceptedRequest) => {
72 | if (interceptedRequest.isInterceptResolutionHandled()) return;
73 | if (interceptedRequest.url().includes("favicon.ico")) {
74 | interceptedRequest.respond({
75 | status: 200,
76 | contentType: "image/png",
77 | body: "Empty",
78 | });
79 | } else {
80 | interceptedRequest.continue(
81 | interceptedRequest.continueRequestOverrides(),
82 | 10,
83 | );
84 | }
85 | });
86 |
87 | return page;
88 | });
89 | }
90 |
91 | module.exports = runBrowser;
92 | module.exports.runPage = runPage;
93 |
--------------------------------------------------------------------------------
/tests/helpers/sequencer.js:
--------------------------------------------------------------------------------
1 | const Sequencer = require("@jest/test-sequencer").default;
2 |
3 | class NamedSequencer extends Sequencer {
4 | sort(tests) {
5 | const copyTests = [...tests];
6 | return copyTests.sort((testA, testB) => (testA.path > testB.path ? 1 : -1));
7 | }
8 | }
9 |
10 | module.exports = NamedSequencer;
11 |
--------------------------------------------------------------------------------
/tests/helpers/session-subscribe.js:
--------------------------------------------------------------------------------
1 | module.exports = async function sessionSubscribe(session) {
2 | session.on("sessionattached", (s) => {
3 | sessionSubscribe(s);
4 | });
5 | session.send("Network.enable");
6 | session.send("Runtime.runIfWaitingForDebugger");
7 | };
8 |
--------------------------------------------------------------------------------
/tests/helpers/setup-test.js:
--------------------------------------------------------------------------------
1 | process.env.CHOKIDAR_USEPOLLING = true;
2 |
3 | jest.setTimeout(400000);
4 |
--------------------------------------------------------------------------------
/tests/helpers/snapshot-resolver.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 | const webpack = require("@rspack/core");
3 |
4 | const [webpackVersion] = webpack.version;
5 | const snapshotExtension = `.snap.webpack${webpackVersion}`;
6 |
7 | module.exports = {
8 | resolveSnapshotPath: (testPath) =>
9 | path.join(
10 | path.dirname(testPath),
11 | "__snapshots__",
12 | `${path.basename(testPath)}${snapshotExtension}`,
13 | ),
14 | resolveTestPath: (snapshotPath) =>
15 | snapshotPath
16 | .replace(`${path.sep}__snapshots__`, "")
17 | .slice(0, -snapshotExtension.length),
18 | testPathForConsistencyCheck: path.join(
19 | "consistency_check",
20 | "__tests__",
21 | "example.test.js",
22 | ),
23 | };
24 |
--------------------------------------------------------------------------------
/tests/helpers/test-server.js:
--------------------------------------------------------------------------------
1 | const webpack = require("@rspack/core");
2 | const { RspackDevServer: Server } = require("@rspack/dev-server");
3 |
4 | let server;
5 |
6 | // start server, returning the full setup of the server
7 | // (both the server and the compiler)
8 | function startFullSetup(config, options, done) {
9 | // disable watching by default for tests
10 | if (typeof options.static === "undefined") {
11 | options.static = false;
12 | } else if (options.static === null) {
13 | // this provides a way of using the default static value
14 | options.static = undefined;
15 | }
16 |
17 | const compiler = webpack(config);
18 |
19 | server = new Server(options, compiler);
20 |
21 | server.startCallback((error) => {
22 | if (error && done) {
23 | return done(error);
24 | }
25 |
26 | if (done) {
27 | done();
28 | }
29 | });
30 |
31 | return {
32 | server,
33 | compiler,
34 | };
35 | }
36 |
37 | function startAwaitingCompilationFullSetup(config, options, done) {
38 | let readyCount = 0;
39 |
40 | const ready = (error) => {
41 | if (error && done) {
42 | done(error);
43 |
44 | return;
45 | }
46 |
47 | readyCount += 1;
48 |
49 | if (readyCount === 2) {
50 | done();
51 | }
52 | };
53 |
54 | const fullSetup = startFullSetup(config, options, ready);
55 |
56 | // wait for compilation, since dev server can start before this
57 | // https://github.com/webpack/webpack-dev-server/issues/847
58 | fullSetup.compiler.hooks.done.tap("done", () => {
59 | ready();
60 | });
61 |
62 | return fullSetup;
63 | }
64 |
65 | function startAwaitingCompilation(config, options, done) {
66 | return startAwaitingCompilationFullSetup(config, options, done).server;
67 | }
68 |
69 | function start(config, options, done) {
70 | // I suspect that almost all tests need to wait for compilation to
71 | // finish, because not doing so leaves open handles for jest,
72 | // in the case where a compilation didn't finish before destroying
73 | // the server and moving on. Thus, the default "start" should wait
74 | // for compilation, and only special cases where you don't expect
75 | // a compilation happen should use startBeforeCompilation
76 | return startAwaitingCompilation(config, options, done);
77 | }
78 |
79 | function close(done) {
80 | if (server) {
81 | server.stopCallback(() => {
82 | server = null;
83 | done();
84 | });
85 | } else {
86 | done();
87 | }
88 | }
89 |
90 | module.exports = {
91 | start,
92 | close,
93 | };
94 |
--------------------------------------------------------------------------------
/tests/helpers/trusted-types-html-generator-plugin.js:
--------------------------------------------------------------------------------
1 | const HTMLContentForIndex = `
2 |
3 |
4 |
5 |
9 |
10 | webpack-dev-server
11 |
12 |
13 | webpack-dev-server is running...
14 |
15 |
16 |
17 | `;
18 |
19 | const HTMLContentForTest = `
20 |
21 |
22 |
23 |
27 |
28 | test
29 |
30 |
31 | Created via HTMLGeneratorPlugin
32 |
33 |
34 | `;
35 |
36 | module.exports = class HTMLGeneratorPlugin {
37 | // eslint-disable-next-line class-methods-use-this
38 | apply(compiler) {
39 | const pluginName = "html-generator-plugin";
40 |
41 | compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
42 | if (compiler.webpack) {
43 | const { RawSource } = compiler.webpack.sources;
44 |
45 | compilation.hooks.processAssets.tap(
46 | {
47 | name: pluginName,
48 | stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
49 | },
50 | () => {
51 | const indexSource = new RawSource(HTMLContentForIndex);
52 | const testSource = new RawSource(HTMLContentForTest);
53 |
54 | compilation.emitAsset("index.html", indexSource);
55 | compilation.emitAsset("test.html", testSource);
56 | },
57 | );
58 | } else {
59 | compilation.hooks.additionalAssets.tap(pluginName, () => {
60 | compilation.emitAsset("index.html", {
61 | source() {
62 | return HTMLContentForIndex;
63 | },
64 | size() {
65 | return HTMLContentForIndex.length;
66 | },
67 | });
68 | compilation.emitAsset("test.html", {
69 | source() {
70 | return HTMLContentForTest;
71 | },
72 | size() {
73 | return HTMLContentForTest.length;
74 | },
75 | });
76 | });
77 | }
78 | });
79 | }
80 | };
81 |
--------------------------------------------------------------------------------
/tests/normalizeOptions.test.ts:
--------------------------------------------------------------------------------
1 | import { type RspackOptions, rspack } from "@rspack/core";
2 | import { type Configuration, RspackDevServer } from "@rspack/dev-server";
3 | import ReactRefreshPlugin from "@rspack/plugin-react-refresh";
4 | // @ts-expect-error
5 | import serializer from "jest-serializer-path";
6 | import customConfig from "./fixtures/provide-plugin-custom/webpack.config";
7 |
8 | expect.addSnapshotSerializer(serializer);
9 |
10 | // The aims of use a cutstom value rather than
11 | // default is to avoid stack overflow trigged
12 | // by `webpack/schemas/WebpackOption.check.js` in debug mode
13 | const ENTRY = "./placeholder.js";
14 | const ENTRY1 = "./placeholder1.js";
15 |
16 | // TODO: node 20 works but node 18 and 16 failed
17 | describe.skip("normalize options snapshot", () => {
18 | it("no options", async () => {
19 | await match({});
20 | });
21 |
22 | it("port string", async () => {
23 | await match({
24 | devServer: {
25 | port: "9000",
26 | },
27 | });
28 | });
29 |
30 | it("additional entires should added", async () => {
31 | expect(
32 | await getAdditionEntries({}, { entry: ["something"] }),
33 | ).toMatchSnapshot();
34 | });
35 |
36 | it("shouldn't have reactRefreshEntry.js by default when in production mode", async () => {
37 | const reactRefreshEntry =
38 | "plugin-react-refresh/client/reactRefreshEntry.js";
39 | const entries1 = await getAdditionEntries(
40 | {},
41 | {
42 | mode: "production",
43 | entry: ["something"],
44 | },
45 | );
46 | expect(entries1.undefined).not.toContain(reactRefreshEntry);
47 | const entries2 = await getAdditionEntries(
48 | {},
49 | {
50 | mode: "production",
51 | entry: ["something"],
52 | plugins: [new ReactRefreshPlugin({ forceEnable: true })],
53 | },
54 | );
55 | expect(entries2.undefined).toContain(reactRefreshEntry);
56 | const entries3 = await getAdditionEntries(
57 | {},
58 | {
59 | mode: "development",
60 | entry: ["something"],
61 | plugins: [new ReactRefreshPlugin()],
62 | },
63 | );
64 | expect(entries3.undefined).toContain(reactRefreshEntry);
65 | const entries4 = await getAdditionEntries(
66 | {},
67 | {
68 | mode: "production",
69 | entry: ["something"],
70 | plugins: [new ReactRefreshPlugin()],
71 | },
72 | );
73 | expect(entries4.undefined).not.toContain(reactRefreshEntry);
74 | });
75 |
76 | it("should apply HMR plugin by default", async () => {
77 | const compiler = rspack({
78 | entry: ENTRY,
79 | stats: "none",
80 | });
81 | const server = new RspackDevServer({}, compiler);
82 | await server.start();
83 | const hmrPlugins = compiler.__internal__builtinPlugins.filter(
84 | (p) => p.name === "HotModuleReplacementPlugin",
85 | );
86 | expect(hmrPlugins.length).toBe(1);
87 | expect(server.options.hot).toBe(true);
88 | await server.stop();
89 | });
90 |
91 | it("should support multi-compiler", async () => {
92 | const compiler = rspack([
93 | {
94 | entry: ENTRY,
95 | stats: "none",
96 | },
97 | {
98 | entry: ENTRY1,
99 | stats: "none",
100 | },
101 | ]);
102 | const server = new RspackDevServer({}, compiler);
103 | await server.start();
104 | await server.stop();
105 | });
106 |
107 | it("should support custom client transport", async () => {
108 | const compiler = rspack(customConfig);
109 | const devServerOptions = {
110 | client: {
111 | webSocketTransport: require.resolve(
112 | "./fixtures/custom-client/CustomSockJSClient",
113 | ),
114 | },
115 | webSocketServer: "sockjs",
116 | };
117 | const server = new RspackDevServer(devServerOptions, compiler);
118 | await server.start();
119 | await server.stop();
120 | });
121 | });
122 |
123 | async function match(config: RspackOptions) {
124 | const compiler = rspack({
125 | ...config,
126 | entry: ENTRY,
127 | stats: "none",
128 | });
129 | const server = new RspackDevServer(
130 | compiler.options.devServer ?? {},
131 | compiler,
132 | );
133 | await server.start();
134 | // it will break ci
135 | //@ts-ignore
136 | server.options.port = undefined;
137 | expect(server.options).toMatchSnapshot();
138 | await server.stop();
139 | }
140 |
141 | async function getAdditionEntries(
142 | serverConfig: Configuration,
143 | config: RspackOptions,
144 | ) {
145 | const compiler = rspack({
146 | ...config,
147 | stats: "none",
148 | entry: ENTRY,
149 | });
150 |
151 | const server = new RspackDevServer(serverConfig, compiler);
152 | await server.start();
153 | const entries = compiler.__internal__builtinPlugins
154 | .filter((p) => p.name === "EntryPlugin")
155 | .map((p) => p.options)
156 | // biome-ignore lint/suspicious/noExplicitAny: _
157 | .reduce>((acc: any, cur: any) => {
158 | const name = cur.options.name;
159 | const request = cur.entry;
160 | if (acc[name]) {
161 | acc[name].import.push(request);
162 | } else {
163 | acc[name] = { import: [request] };
164 | }
165 | return acc;
166 | }, {});
167 | // some hack for snapshot
168 | const value = Object.fromEntries(
169 | Object.entries(entries).map(([key, item]) => {
170 | // @ts-expect-error
171 | const replaced = item.import?.map((entry) => {
172 | const array = entry
173 | .replace(/\\/g, "/")
174 | .replace(/port=\d+/g, "")
175 | .split("/");
176 | return `/${array.slice(-3).join("/")}`;
177 | });
178 | return [key, replaced];
179 | }),
180 | );
181 | await server.stop();
182 | return value;
183 | }
184 |
--------------------------------------------------------------------------------
/tests/placeholder.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/placeholder.js
--------------------------------------------------------------------------------
/tests/placeholder1.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/web-infra-dev/rspack-dev-server/738b8a2e076a43c07e3d56fa71e48f7c5663617f/tests/placeholder1.js
--------------------------------------------------------------------------------
/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": false,
6 | "rootDir": "../"
7 | },
8 | "include": ["../src", "../tests", "../client-src"],
9 | "references": []
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "sourceMap": false,
5 | "declarationMap": false
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.client.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "module": "ES2020",
5 | "target": "ES5",
6 | "outDir": "client",
7 | "rootDir": "client-src",
8 | "composite": false,
9 | "sourceMap": false,
10 | "declarationMap": false,
11 | "declaration": false
12 | },
13 | "include": ["client-src"]
14 | }
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "NodeNext",
4 | "moduleResolution": "NodeNext",
5 | "target": "ES2021",
6 | "esModuleInterop": true,
7 | "declaration": true,
8 | "isolatedModules": true,
9 | "sourceMap": true,
10 | "declarationMap": true,
11 | "composite": true,
12 | "forceConsistentCasingInFileNames": true,
13 | "allowJs": true,
14 | "checkJs": true,
15 | "strict": true,
16 | "skipLibCheck": true,
17 | "noUnusedLocals": true,
18 | "outDir": "dist",
19 | "rootDir": "src"
20 | },
21 | "ts-node": {
22 | "transpileOnly": true
23 | },
24 | "include": ["src"]
25 | }
26 |
--------------------------------------------------------------------------------