Add Gzip support for JSON pages#571
Conversation
| @@ -0,0 +1,22 @@ | |||
| export default class JsonPagesPlugin { | |||
There was a problem hiding this comment.
@nkzawa This is my first webpack plugin.
Could you check whether I have done something ugly here?
|
|
||
| while (true) { | ||
| // gzip only 10 assets in parallel at a time. | ||
| const currentChunk = allAssets.splice(0, 10) |
There was a problem hiding this comment.
@rauchg it didn't sounds nice to gzip all at once in parallel to me.
Is this something I don't wanna worry?
server/build/gzip.js
Outdated
| resolve(pages) | ||
| }) | ||
| }) | ||
| } |
There was a problem hiding this comment.
Why we don't use glob-promise ?
There was a problem hiding this comment.
Yeah! I'll try to use it.
server/build/gzip.js
Outdated
| const currentChunk = allAssets.splice(0, 10) | ||
| if (currentChunk.length === 0) break | ||
|
|
||
| const promises = currentChunk.map((filePath) => gzip(filePath)) |
There was a problem hiding this comment.
It can be currentChunk.map(filePath) ?
There was a problem hiding this comment.
I meant currentChunk.map(gzip)
| const newContent = JSON.stringify({ component: content }) | ||
| page.source = () => newContent | ||
| page.size = () => newContent.length | ||
| page.jsoned = true |
There was a problem hiding this comment.
Should we change the extension to .json ?
There was a problem hiding this comment.
Yes. That can be done. I'll try it.
server/render.js
Outdated
| send(req, path) | ||
| .on('error', (err) => { | ||
| if (err.code === 'ENOENT') { | ||
| this.render404(req, res).then(resolve, reject) |
There was a problem hiding this comment.
Good catch. I'll move that to here too.
server/render.js
Outdated
| ]) | ||
|
|
||
| const component = JSON.parse(componentJson).component | ||
| const errorComponent = JSON.parse(errorComponentJson).component |
There was a problem hiding this comment.
We should cache the parsed result.
|
@nkzawa Implemented all the suggestion you made. |
| if (fn) { | ||
| const data = obj.data || [] | ||
| fn(...data) | ||
| const route = data[0].replace(/[index]*\.json$/, '') |
There was a problem hiding this comment.
@nkzawa
I had to do this because now these files routes have .json extension.
Do you know why this has changed?
Is there any better way to deal with this?
There was a problem hiding this comment.
Please change server/hot-reloader.js instead of this file. Maybe toRoute method.
server/build/webpack.js
Outdated
| ? [join(__dirname, '..', '..', 'client/webpack-hot-middleware-client')] : [] | ||
| for (const p of pages) { | ||
| entry[join('bundles', p)] = defaultEntries.concat([`./${p}?entry`]) | ||
| entry[pagePathToJson(join('bundles', p))] = defaultEntries.concat([`./${p}?entry`]) |
There was a problem hiding this comment.
I think, ideally, extensions should be changed on JsonPagesPlugin. Is it difficult ?
There was a problem hiding this comment.
Nope. That's not hard. I think that makes sense. I'll do it.
| export default read | ||
| export const cache = {} | ||
|
|
||
| read.cache = cache |
There was a problem hiding this comment.
This is used on hot-reloader.js too. I think we need to fix it.
| .on('error', (err) => { | ||
| if (err.code === 'ENOENT') { | ||
| res.statusCode = 404 | ||
| res.end('Not Found') |
There was a problem hiding this comment.
Maybe this change is acceptable, but it'd be better if we can show the original 404.
There was a problem hiding this comment.
In the orginal 404, it sends a bunch of HTML too. It's okay for pages, but this is just a JSON endpoint. We don't need that. (Since user won't access these files directly)
There was a problem hiding this comment.
This is not only for JSON endpoint, but it's also for /static. Users might access old static file URL and see 404. Anyway I think it's ok for now.
There was a problem hiding this comment.
I'll work a separate PR for that.
|
|
||
| // Delete existing json pages | ||
| // Otherwise, we might keep JSON pages for deleted pages. | ||
| jsonPages.forEach((pagePath) => delete compilation.assets[pagePath]) |
There was a problem hiding this comment.
I think we don't need this since compilation instance is recreated on each build. So I think there is no json pages remaining, or is there ?
server/render.js
Outdated
| } | ||
|
|
||
| const gzipPath = `${path}.gz` | ||
| const exists = await fs.exists(gzipPath) |
There was a problem hiding this comment.
this is a deprecated API.
There was a problem hiding this comment.
Oh yeah! Seems like I need to read along the Node.js API again :)
There was a problem hiding this comment.
Seems like fs.access is not recommended for this: https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback
I'll work on with renderStatic for this to get rid of this issue.
There was a problem hiding this comment.
@nkzawa Check now.
I figured, it's safe for us to use fs.access
|
👍 amazing |
| compiler.plugin('after-compile', (compilation, callback) => { | ||
| const pages = Object | ||
| .keys(compilation.assets) | ||
| .filter((filename) => /^bundles\/pages.*\.js$/.test(filename)) |
There was a problem hiding this comment.
This regex doesn't match the way one could wish for in windows, causing pages not to be compiled to json, causing issue #597 thus making most tests fail on windows.
Related to #555
Fixes #568
Now we are serving JSON pages directly from the file system for most of the time. We do that with a custom webpack plugin.
So, now we could add gzip support for pages pretty quickly.
Since now we serve JSON pages directly from the filesystem, ETags are sent automatically and it fixes #568