Skip to content

Commit 8a0bb32

Browse files
authored
Allow Writing Files to Disk (#287)
* fixes #286. writeToDisk option * add filter function capability
1 parent 08207cc commit 8a0bb32

File tree

11 files changed

+617
-1493
lines changed

11 files changed

+617
-1493
lines changed

README.md

+27-1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,32 @@ The module accepts an `Object` containing options for file watching, which is
191191
passed directly to the compiler provided. For more information on watch options
192192
please see the [webpack documentation](https://webpack.js.org/configuration/watch/#watchoptions)
193193

194+
### writeToDisk
195+
196+
Type: `Boolean|Function`
197+
Default: `false`
198+
199+
If true, the option will instruct the module to write files to the configured
200+
location on disk as specified in your `webpack` config file. _Setting
201+
`writeToDisk: true` won't change the behavior of the `webpack-dev-middleware`,
202+
and bundle files accessed through the browser will still be served from memory._
203+
This option provides the same capabilities as the
204+
[`WriteFilePlugin`](https://github.com/gajus/write-file-webpack-plugin/pulls).
205+
206+
This option also accepts a `Function` value, which can be used to filter which
207+
files are written to disk. The function follows the same premise as
208+
[`Array#filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
209+
in which a return value of `false` _will not_ write the file, and a return value
210+
of `true` _will_ write the file to disk. eg.
211+
212+
```js
213+
{
214+
writeToDisk: (filePath) {
215+
return /superman\.css$/.test(filePath);
216+
}
217+
}
218+
```
219+
194220
## API
195221

196222
`webpack-dev-middleware` also provides convenience methods that can be use to
@@ -401,4 +427,4 @@ We welcome your contributions! Please have a read of [CONTRIBUTING.md](CONTRIBUT
401427
[middleware-url]: https://github.com/webpack/webpack-dev-middleware
402428
[stack-url]: https://stackoverflow.com/questions/tagged/webpack-dev-middleware
403429
[uglify-url]: https://github.com/webpack-contrib/uglifyjs-webpack-plugin
404-
[wjo-url]: https://github.com/webpack/webpack.js.org
430+
[wjo-url]: https://github.com/webpack/webpack.js.org

index.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ const mime = require('mime');
44
const createContext = require('./lib/context');
55
const middleware = require('./lib/middleware');
66
const reporter = require('./lib/reporter');
7-
const { getFilenameFromUrl, noop, ready, setFs } = require('./lib/util');
7+
const { setFs, toDisk } = require('./lib/fs');
8+
const { getFilenameFromUrl, noop, ready } = require('./lib/util');
89

910
require('loud-rejection/register');
1011

@@ -20,7 +21,8 @@ const defaults = {
2021
},
2122
watchOptions: {
2223
aggregateTimeout: 200
23-
}
24+
},
25+
writeToDisk: false
2426
};
2527

2628
module.exports = function wdm(compiler, opts) {
@@ -59,6 +61,10 @@ module.exports = function wdm(compiler, opts) {
5961
context.state = true;
6062
}
6163

64+
if (options.writeToDisk) {
65+
toDisk(context);
66+
}
67+
6268
setFs(context, compiler);
6369

6470
return Object.assign(middleware(context), {

lib/fs.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const chalk = require('chalk'); // eslint-disable-line import/no-extraneous-dependencies
6+
const MemoryFileSystem = require('memory-fs');
7+
const pathabs = require('path-is-absolute');
8+
const NodeOutputFileSystem = require('webpack/lib/node/NodeOutputFileSystem');
9+
const DevMiddlewareError = require('./DevMiddlewareError');
10+
11+
const { mkdirp } = new NodeOutputFileSystem();
12+
13+
module.exports = {
14+
toDisk(context) {
15+
context.compiler.hooks.afterEmit.tap('WebpackDevMiddleware', (compilation) => {
16+
const { assets, compiler } = compilation;
17+
const { log } = context;
18+
const { writeToDisk: filter } = context.options;
19+
let { outputPath } = compiler;
20+
21+
if (outputPath === '/') {
22+
outputPath = compiler.context;
23+
}
24+
25+
for (const assetPath of Object.keys(assets)) {
26+
const asset = assets[assetPath];
27+
const source = asset.source();
28+
const isAbsolute = pathabs(assetPath);
29+
const writePath = isAbsolute ? assetPath : path.join(outputPath, assetPath);
30+
const relativePath = path.relative(process.cwd(), writePath);
31+
const allowWrite = filter && typeof filter === 'function' ? filter(writePath) : true;
32+
33+
if (allowWrite) {
34+
let output = source;
35+
36+
mkdirp.sync(path.dirname(writePath));
37+
38+
if (Array.isArray(source)) {
39+
output = source.join('\n');
40+
}
41+
42+
try {
43+
fs.writeFileSync(writePath, output, 'utf-8');
44+
log.debug(chalk`{cyan Asset written to disk}: ${relativePath}`);
45+
} catch (e) {
46+
log.error(`Unable to write asset to disk:\n${e}`);
47+
}
48+
}
49+
}
50+
});
51+
},
52+
53+
setFs(context, compiler) {
54+
if (typeof compiler.outputPath === 'string' && !pathabs.posix(compiler.outputPath) && !pathabs.win32(compiler.outputPath)) {
55+
throw new DevMiddlewareError('`output.path` needs to be an absolute path or `/`.');
56+
}
57+
58+
let fileSystem;
59+
// store our files in memory
60+
const isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;
61+
62+
if (isMemoryFs) {
63+
fileSystem = compiler.outputFileSystem;
64+
} else {
65+
fileSystem = new MemoryFileSystem();
66+
compiler.outputFileSystem = fileSystem;
67+
}
68+
69+
context.fs = fileSystem;
70+
}
71+
};

lib/util.js

+1-22
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
const { parse } = require('url');
44
const querystring = require('querystring');
5-
const MemoryFileSystem = require('memory-fs');
65
const pathabs = require('path-is-absolute');
76
const parseRange = require('range-parser');
87
const urlJoin = require('url-join');
9-
const DevMiddlewareError = require('./DevMiddlewareError');
108

119
const HASH_REGEXP = /[0-9a-f]{10,}/;
1210

@@ -166,24 +164,5 @@ module.exports = {
166164

167165
noop: () => {},
168166

169-
ready,
170-
171-
setFs(context, compiler) {
172-
if (typeof compiler.outputPath === 'string' && !pathabs.posix(compiler.outputPath) && !pathabs.win32(compiler.outputPath)) {
173-
throw new DevMiddlewareError('`output.path` needs to be an absolute path or `/`.');
174-
}
175-
176-
let fs;
177-
// store our files in memory
178-
const isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;
179-
180-
if (isMemoryFs) {
181-
fs = compiler.outputFileSystem;
182-
} else {
183-
fs = new MemoryFileSystem();
184-
compiler.outputFileSystem = fs;
185-
}
186-
187-
context.fs = fs;
188-
}
167+
ready
189168
};

0 commit comments

Comments
 (0)