Skip to content

Commit

Permalink
perf: remove outputFileSystem option
Browse files Browse the repository at this point in the history
  • Loading branch information
chenjiahan committed Aug 21, 2024
1 parent a8924b9 commit bf0e25e
Show file tree
Hide file tree
Showing 6 changed files with 1 addition and 275 deletions.
101 changes: 0 additions & 101 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ app.listen(3000, () => console.log("Example app listening on port 3000!"));
| **[`index`](#index)** | `Boolean\|String` | `index.html` | If `false` (but not `undefined`), the server will not respond to requests to the root URL. |
| **[`publicPath`](#publicpath)** | `String` | `output.publicPath` (from a configuration) | The public path that the middleware is bound to. |
| **[`writeToDisk`](#writetodisk)** | `Boolean\|Function` | `false` | Instructs the module to write files to the configured location on disk as specified in your `webpack` configuration. |
| **[`outputFileSystem`](#outputfilesystem)** | `Object` | [`memfs`](https://github.com/streamich/memfs) | Set the default file system which will be used by webpack as primary destination of generated files. |

The middleware accepts an `options` Object. The following is a property reference for the Object.

Expand Down Expand Up @@ -116,34 +115,6 @@ middleware(compiler, {
});
```

### outputFileSystem

Type: `Object`
Default: [memfs](https://github.com/streamich/memfs)

Set the default file system which will be used by webpack as primary destination of generated files.
This option isn't affected by the [writeToDisk](#writeToDisk) option.

You have to provide `.join()` and `mkdirp` method to the `outputFileSystem` instance manually for compatibility with `webpack@4`.

This can be done simply by using `path.join`:

```js
const webpack = require("webpack");
const path = require("path");
const myOutputFileSystem = require("my-fs");
const mkdirp = require("mkdirp");

myOutputFileSystem.join = path.join.bind(path); // no need to bind
myOutputFileSystem.mkdirp = mkdirp.bind(mkdirp); // no need to bind

const compiler = webpack({
/* Webpack configuration */
});

middleware(compiler, { outputFileSystem: myOutputFileSystem });
```

## API

`webpack-dev-middleware` also provides convenience methods that can be use to
Expand Down Expand Up @@ -311,78 +282,6 @@ app.use(
app.listen(3000, () => console.log("Example app listening on port 3000!"));
```

## Server-Side Rendering

_Note: this feature is experimental and may be removed or changed completely in the future._

In order to develop an app using server-side rendering, we need access to the
[`stats`](https://github.com/webpack/docs/wiki/node.js-api#stats), which is
generated with each build.

With server-side rendering enabled, `webpack-dev-middleware` sets the `stats` to `res.locals.webpack.devMiddleware.stats`
and the filesystem to `res.locals.webpack.devMiddleware.outputFileSystem` before invoking the next middleware,
allowing a developer to render the page body and manage the response to clients.

_Note: Requests for bundle files will still be handled by
`webpack-dev-middleware` and all requests will be pending until the build
process is finished with server-side rendering enabled._

Example Implementation:

```js
const express = require("express");
const webpack = require("webpack");
const compiler = webpack({
/* Webpack configuration */
});
const isObject = require("is-object");
const middleware = require("webpack-dev-middleware");

const app = new express();

// This function makes server rendering of asset references consistent with different webpack chunk/entry configurations
function normalizeAssets(assets) {
if (isObject(assets)) {
return Object.values(assets);
}

return Array.isArray(assets) ? assets : [assets];
}

app.use(middleware(compiler));

// The following middleware would not be invoked until the latest build is finished.
app.use((req, res) => {
const { devMiddleware } = res.locals.webpack;
const outputFileSystem = devMiddleware.outputFileSystem;
const jsonWebpackStats = devMiddleware.stats.toJson();
const { assetsByChunkName, outputPath } = jsonWebpackStats;

// Then use `assetsByChunkName` for server-side rendering
// For example, if you have only one main chunk:
res.send(`
<html>
<head>
<title>My App</title>
<style>
${normalizeAssets(assetsByChunkName.main)
.filter((path) => path.endsWith(".css"))
.map((path) => outputFileSystem.readFileSync(path.join(outputPath, path)))
.join("\n")}
</style>
</head>
<body>
<div id="root"></div>
${normalizeAssets(assetsByChunkName.main)
.filter((path) => path.endsWith(".js"))
.map((path) => `<script src="${path}"></script>`)
.join("\n")}
</body>
</html>
`);
});
```

## Support

We do our best to keep Issues in the repository focused on bugs, features, and
Expand Down
1 change: 0 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ const noop = () => {};
* @typedef {Object} Options
* @property {boolean | ((targetPath: string) => boolean)} [writeToDisk]
* @property {NonNullable<Configuration["output"]>["publicPath"]} [publicPath]
* @property {OutputFileSystem} [outputFileSystem]
* @property {boolean | string} [index]
* @property {boolean} [lastModified]
*/
Expand Down
7 changes: 1 addition & 6 deletions src/utils/setupOutputFileSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,8 @@ const memfs = require("memfs");
function setupOutputFileSystem(context) {
let outputFileSystem;

if (context.options.outputFileSystem) {
const { outputFileSystem: outputFileSystemFromOptions } = context.options;

outputFileSystem = outputFileSystemFromOptions;
}
// Don't use `memfs` when developer wants to write everything to a disk, because it doesn't make sense.
else if (context.options.writeToDisk !== true) {
if (context.options.writeToDisk !== true) {
outputFileSystem = memfs.createFsFromVolume(new memfs.Volume());
} else {
const isMultiCompiler =
Expand Down
149 changes: 0 additions & 149 deletions test/middleware.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import express from "express";
import router from "router";
import finalhandler from "finalhandler";
import request from "supertest";
import memfs, { createFsFromVolume, Volume } from "memfs";
import del from "del";

import { Stats } from "webpack";
Expand Down Expand Up @@ -3524,154 +3523,6 @@ describe.each([
});
});

describe("outputFileSystem option", () => {
describe("should work with an unspecified value", () => {
let compiler;

beforeAll(async () => {
compiler = getCompiler(webpackConfig);

[server, req, instance] = await frameworkFactory(
name,
framework,
compiler,
);
});

afterAll(async () => {
await close(server, instance);
});

it('should use the "memfs" package by default', () => {
const { Stats } = memfs;

expect(new compiler.outputFileSystem.Stats()).toBeInstanceOf(Stats);
expect(new instance.context.outputFileSystem.Stats()).toBeInstanceOf(
Stats,
);
});
});

describe("should work with the configured value (native fs)", () => {
let compiler;

beforeAll(async () => {
compiler = getCompiler(webpackConfig);

const configuredFs = fs;

configuredFs.join = path.join.bind(path);
configuredFs.mkdirp = () => {};

[server, req, instance] = await frameworkFactory(
name,
framework,
compiler,
{
outputFileSystem: configuredFs,
},
);
});

afterAll(async () => {
await close(server, instance);
});

it("should use the configurated output filesystem", () => {
const { Stats } = fs;

expect(new compiler.outputFileSystem.Stats()).toBeInstanceOf(Stats);
expect(new instance.context.outputFileSystem.Stats()).toBeInstanceOf(
Stats,
);
expect(compiler.outputFileSystem).toHaveProperty("join");
expect(compiler.outputFileSystem).toHaveProperty("mkdirp");
});
});

describe("should work with the configured value (memfs)", () => {
let compiler;

beforeAll(async () => {
compiler = getCompiler(webpackConfig);

const configuredFs = createFsFromVolume(new Volume());

configuredFs.join = path.join.bind(path);
configuredFs.mkdirp = () => {};

[server, req, instance] = await frameworkFactory(
name,
framework,
compiler,
{
outputFileSystem: configuredFs,
},
);
});

afterAll(async () => {
await close(server, instance);
});

it("should use the configured output filesystem", () => {
const { Stats } = memfs;

expect(new compiler.outputFileSystem.Stats()).toBeInstanceOf(Stats);
expect(new instance.context.outputFileSystem.Stats()).toBeInstanceOf(
Stats,
);
expect(compiler.outputFileSystem).toHaveProperty("join");
expect(compiler.outputFileSystem).toHaveProperty("mkdirp");
expect(compiler.outputFileSystem).toHaveProperty("mkdirSync");
});
});

describe("should work with the configured value in multi-compiler mode (native fs)", () => {
let compiler;

beforeAll(async () => {
compiler = getCompiler(webpackMultiConfig);

const configuredFs = fs;

configuredFs.join = path.join.bind(path);
configuredFs.mkdirp = () => {};

[server, req, instance] = await frameworkFactory(
name,
framework,
compiler,
{
outputFileSystem: configuredFs,
},
);
});

afterAll(async () => {
await close(server, instance);
});

it("should use configured output filesystems", () => {
const { Stats } = fs;

for (const childCompiler of compiler.compilers) {
expect(new childCompiler.outputFileSystem.Stats()).toBeInstanceOf(
Stats,
);
expect(childCompiler.outputFileSystem).toHaveProperty("join");
expect(childCompiler.outputFileSystem).toHaveProperty("mkdirp");
}

expect(new instance.context.outputFileSystem.Stats()).toBeInstanceOf(
Stats,
);
expect(instance.context.outputFileSystem).toHaveProperty("join");
expect(instance.context.outputFileSystem).toHaveProperty("mkdirp");
});
});
});

describe("index option", () => {
describe('should work with "false" value', () => {
beforeAll(async () => {
Expand Down
16 changes: 0 additions & 16 deletions test/utils/setupOutputFileSystem.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,4 @@ describe("setupOutputFileSystem", () => {
expect(comp.outputFileSystem).toBeTruthy();
});
});

it("should use provided fs with correct methods", () => {
const context = {
compiler: {},
options: {
outputFileSystem: {
join: () => {},
mkdirp: () => {},
},
},
};

setupOutputFileSystem(context);

expect(context.outputFileSystem).toEqual(context.options.outputFileSystem);
});
});
2 changes: 0 additions & 2 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ export = wdm;
* @typedef {Object} Options
* @property {boolean | ((targetPath: string) => boolean)} [writeToDisk]
* @property {NonNullable<Configuration["output"]>["publicPath"]} [publicPath]
* @property {OutputFileSystem} [outputFileSystem]
* @property {boolean | string} [index]
* @property {boolean} [lastModified]
*/
Expand Down Expand Up @@ -259,7 +258,6 @@ type Options<
> = {
writeToDisk?: boolean | ((targetPath: string) => boolean) | undefined;
publicPath?: NonNullable<Configuration["output"]>["publicPath"];
outputFileSystem?: OutputFileSystem | undefined;
index?: string | boolean | undefined;
lastModified?: boolean | undefined;
};
Expand Down

0 comments on commit bf0e25e

Please sign in to comment.