Skip to content

Commit

Permalink
Allow Writing Files to Disk (#287)
Browse files Browse the repository at this point in the history
* fixes #286. writeToDisk option

* add filter function capability
  • Loading branch information
shellscape authored Mar 24, 2018
1 parent 08207cc commit 8a0bb32
Show file tree
Hide file tree
Showing 11 changed files with 617 additions and 1,493 deletions.
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,32 @@ The module accepts an `Object` containing options for file watching, which is
passed directly to the compiler provided. For more information on watch options
please see the [webpack documentation](https://webpack.js.org/configuration/watch/#watchoptions)

### writeToDisk

Type: `Boolean|Function`
Default: `false`

If true, the option will instruct the module to write files to the configured
location on disk as specified in your `webpack` config file. _Setting
`writeToDisk: true` won't change the behavior of the `webpack-dev-middleware`,
and bundle files accessed through the browser will still be served from memory._
This option provides the same capabilities as the
[`WriteFilePlugin`](https://github.com/gajus/write-file-webpack-plugin/pulls).

This option also accepts a `Function` value, which can be used to filter which
files are written to disk. The function follows the same premise as
[`Array#filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
in which a return value of `false` _will not_ write the file, and a return value
of `true` _will_ write the file to disk. eg.

```js
{
writeToDisk: (filePath) {
return /superman\.css$/.test(filePath);
}
}
```

## API

`webpack-dev-middleware` also provides convenience methods that can be use to
Expand Down Expand Up @@ -401,4 +427,4 @@ We welcome your contributions! Please have a read of [CONTRIBUTING.md](CONTRIBUT
[middleware-url]: https://github.com/webpack/webpack-dev-middleware
[stack-url]: https://stackoverflow.com/questions/tagged/webpack-dev-middleware
[uglify-url]: https://github.com/webpack-contrib/uglifyjs-webpack-plugin
[wjo-url]: https://github.com/webpack/webpack.js.org
[wjo-url]: https://github.com/webpack/webpack.js.org
10 changes: 8 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const mime = require('mime');
const createContext = require('./lib/context');
const middleware = require('./lib/middleware');
const reporter = require('./lib/reporter');
const { getFilenameFromUrl, noop, ready, setFs } = require('./lib/util');
const { setFs, toDisk } = require('./lib/fs');
const { getFilenameFromUrl, noop, ready } = require('./lib/util');

require('loud-rejection/register');

Expand All @@ -20,7 +21,8 @@ const defaults = {
},
watchOptions: {
aggregateTimeout: 200
}
},
writeToDisk: false
};

module.exports = function wdm(compiler, opts) {
Expand Down Expand Up @@ -59,6 +61,10 @@ module.exports = function wdm(compiler, opts) {
context.state = true;
}

if (options.writeToDisk) {
toDisk(context);
}

setFs(context, compiler);

return Object.assign(middleware(context), {
Expand Down
71 changes: 71 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use strict';

const fs = require('fs');
const path = require('path');
const chalk = require('chalk'); // eslint-disable-line import/no-extraneous-dependencies
const MemoryFileSystem = require('memory-fs');
const pathabs = require('path-is-absolute');
const NodeOutputFileSystem = require('webpack/lib/node/NodeOutputFileSystem');
const DevMiddlewareError = require('./DevMiddlewareError');

const { mkdirp } = new NodeOutputFileSystem();

module.exports = {
toDisk(context) {
context.compiler.hooks.afterEmit.tap('WebpackDevMiddleware', (compilation) => {
const { assets, compiler } = compilation;
const { log } = context;
const { writeToDisk: filter } = context.options;
let { outputPath } = compiler;

if (outputPath === '/') {
outputPath = compiler.context;
}

for (const assetPath of Object.keys(assets)) {
const asset = assets[assetPath];
const source = asset.source();
const isAbsolute = pathabs(assetPath);
const writePath = isAbsolute ? assetPath : path.join(outputPath, assetPath);
const relativePath = path.relative(process.cwd(), writePath);
const allowWrite = filter && typeof filter === 'function' ? filter(writePath) : true;

if (allowWrite) {
let output = source;

mkdirp.sync(path.dirname(writePath));

if (Array.isArray(source)) {
output = source.join('\n');
}

try {
fs.writeFileSync(writePath, output, 'utf-8');
log.debug(chalk`{cyan Asset written to disk}: ${relativePath}`);
} catch (e) {
log.error(`Unable to write asset to disk:\n${e}`);
}
}
}
});
},

setFs(context, compiler) {
if (typeof compiler.outputPath === 'string' && !pathabs.posix(compiler.outputPath) && !pathabs.win32(compiler.outputPath)) {
throw new DevMiddlewareError('`output.path` needs to be an absolute path or `/`.');
}

let fileSystem;
// store our files in memory
const isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;

if (isMemoryFs) {
fileSystem = compiler.outputFileSystem;
} else {
fileSystem = new MemoryFileSystem();
compiler.outputFileSystem = fileSystem;
}

context.fs = fileSystem;
}
};
23 changes: 1 addition & 22 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

const { parse } = require('url');
const querystring = require('querystring');
const MemoryFileSystem = require('memory-fs');
const pathabs = require('path-is-absolute');
const parseRange = require('range-parser');
const urlJoin = require('url-join');
const DevMiddlewareError = require('./DevMiddlewareError');

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

Expand Down Expand Up @@ -166,24 +164,5 @@ module.exports = {

noop: () => {},

ready,

setFs(context, compiler) {
if (typeof compiler.outputPath === 'string' && !pathabs.posix(compiler.outputPath) && !pathabs.win32(compiler.outputPath)) {
throw new DevMiddlewareError('`output.path` needs to be an absolute path or `/`.');
}

let fs;
// store our files in memory
const isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;

if (isMemoryFs) {
fs = compiler.outputFileSystem;
} else {
fs = new MemoryFileSystem();
compiler.outputFileSystem = fs;
}

context.fs = fs;
}
ready
};
Loading

0 comments on commit 8a0bb32

Please sign in to comment.