Skip to content

Commit 6b5ba21

Browse files
dlebedynskyigregberge
authored andcommitted
feat(webpack-plugin): add writeToDisk option (#161)
1 parent 3b5b115 commit 6b5ba21

File tree

2 files changed

+121
-23
lines changed

2 files changed

+121
-23
lines changed

packages/webpack-plugin/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ module.exports = {
2020
}
2121
```
2222

23+
## API
24+
25+
### LoadablePlugin
26+
27+
Create a webpack loadable plugin.
28+
29+
| Arguments | Description |
30+
| --------------------- | ------------------------------------------------- |
31+
| `options` | Optional options |
32+
| `options.filename` | Stats filename (default to `loadable-stats.json`) |
33+
| `options.writeToDisk` | Always write assets to disk (default to `false`) |
34+
35+
```js
36+
new LoadablePlugin({ filename: 'stats.json', writeToDisk: true })
37+
```
38+
39+
> Writing file to disk can be useful if you are using `razzle` or `webpack-dev-server`.
40+
2341
## License
2442

2543
MIT

packages/webpack-plugin/src/index.js

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,113 @@
1+
const path = require('path')
2+
const fs = require('fs')
3+
14
class LoadablePlugin {
2-
constructor({ filename = 'loadable-stats.json' } = {}) {
3-
this.opts = { filename }
5+
constructor({ filename = 'loadable-stats.json', writeToDisk = false } = {}) {
6+
this.opts = { filename, writeToDisk }
7+
}
8+
9+
handleEmit = (hookCompiler, callback) => {
10+
const stats = hookCompiler.getStats().toJson({
11+
hash: true,
12+
publicPath: true,
13+
assets: true,
14+
chunks: false,
15+
modules: false,
16+
source: false,
17+
errorDetails: false,
18+
timings: false,
19+
})
20+
const result = JSON.stringify(stats, null, 2)
21+
22+
hookCompiler.assets[this.opts.filename] = {
23+
source() {
24+
return result
25+
},
26+
size() {
27+
return result.length
28+
},
29+
}
30+
31+
if (this.opts.writeToDisk) {
32+
this.writeAssetsFile(result)
33+
}
34+
35+
callback()
36+
}
37+
38+
/**
39+
* Check if request is from Dev Server
40+
* aka webpack-dev-server
41+
* @method isRequestFromDevServer
42+
* @returns {boolean} - True or False
43+
*/
44+
isRequestFromDevServer = () => {
45+
if (process.argv.some(arg => arg.includes('webpack-dev-server'))) {
46+
return true
47+
}
48+
return (
49+
this.compiler.outputFileSystem &&
50+
this.compiler.outputFileSystem.constructor.name === 'MemoryFileSystem'
51+
)
52+
}
53+
54+
/**
55+
* Get assets manifest output path
56+
*
57+
* @method getManifestOutputPath
58+
* @returns {string} - Output path containing path + filename.
59+
*/
60+
getManifestOutputPath = () => {
61+
if (path.isAbsolute(this.opts.filename)) {
62+
return this.opts.filename
63+
}
64+
65+
if (this.isRequestFromDevServer() && this.compiler.options.devServer) {
66+
let outputPath =
67+
this.compiler.options.devServer.outputPath ||
68+
this.compiler.outputPath ||
69+
'/'
70+
71+
if (outputPath === '/') {
72+
// eslint-disable-next-line no-console
73+
console.warn(
74+
'Please use an absolute path in options.output when using webpack-dev-server.',
75+
)
76+
outputPath = this.compiler.context || process.cwd()
77+
}
78+
79+
return path.resolve(outputPath, this.opts.filename)
80+
}
81+
82+
return path.resolve(this.compiler.outputPath, this.opts.filename)
83+
}
84+
85+
/**
86+
* Write Assets Manifest file
87+
* @method writeAssetsFile
88+
*/
89+
writeAssetsFile = manifest => {
90+
const filePath = this.getManifestOutputPath()
91+
const fileDir = path.dirname(filePath)
92+
93+
try {
94+
if (!fs.existsSync(fileDir)) {
95+
fs.mkdirSync(fileDir)
96+
}
97+
} catch (err) {
98+
if (err.code !== 'EEXIST') {
99+
throw err
100+
}
101+
}
102+
103+
fs.writeFileSync(filePath, manifest)
4104
}
5105

6106
apply(compiler) {
7107
// Add a custom output.jsonpFunction: __LOADABLE_LOADED_CHUNKS__
8108
compiler.options.output.jsonpFunction = '__LOADABLE_LOADED_CHUNKS__'
9109

10-
compiler.hooks.emit.tap('@loadable/webpack-plugin', hookCompiler => {
11-
const stats = hookCompiler.getStats().toJson({
12-
hash: true,
13-
publicPath: true,
14-
assets: true,
15-
chunks: false,
16-
modules: false,
17-
source: false,
18-
errorDetails: false,
19-
timings: false,
20-
})
21-
const result = JSON.stringify(stats, null, 2)
22-
hookCompiler.assets[this.opts.filename] = {
23-
source() {
24-
return result
25-
},
26-
size() {
27-
return result.length
28-
},
29-
}
30-
})
110+
compiler.hooks.emit.tapAsync('@loadable/webpack-plugin', this.handleEmit)
31111
}
32112
}
33113

0 commit comments

Comments
 (0)