Skip to content

Add Gzip support for JSON pages#571

Merged
nkzawa merged 18 commits intovercel:masterfrom
arunoda:gzip-on-json-pages
Dec 31, 2016
Merged

Add Gzip support for JSON pages#571
nkzawa merged 18 commits intovercel:masterfrom
arunoda:gzip-on-json-pages

Conversation

@arunoda
Copy link
Copy Markdown
Contributor

@arunoda arunoda commented Dec 30, 2016

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

@@ -0,0 +1,22 @@
export default class JsonPagesPlugin {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkzawa This is my first webpack plugin.
Could you check whether I have done something ugly here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me 👍


while (true) {
// gzip only 10 assets in parallel at a time.
const currentChunk = allAssets.splice(0, 10)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rauchg it didn't sounds nice to gzip all at once in parallel to me.
Is this something I don't wanna worry?

@rauchg rauchg mentioned this pull request Dec 30, 2016
3 tasks
resolve(pages)
})
})
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we don't use glob-promise ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah! I'll try to use it.

const currentChunk = allAssets.splice(0, 10)
if (currentChunk.length === 0) break

const promises = currentChunk.map((filePath) => gzip(filePath))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be currentChunk.map(filePath) ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't get this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant currentChunk.map(gzip)

const newContent = JSON.stringify({ component: content })
page.source = () => newContent
page.size = () => newContent.length
page.jsoned = true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change the extension to .json ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. That can be done. I'll try it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

server/render.js Outdated
send(req, path)
.on('error', (err) => {
if (err.code === 'ENOENT') {
this.render404(req, res).then(resolve, reject)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't resolve this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should cache the parsed result.

@arunoda
Copy link
Copy Markdown
Contributor Author

arunoda commented Dec 30, 2016

@nkzawa Implemented all the suggestion you made.

if (fn) {
const data = obj.data || []
fn(...data)
const route = data[0].replace(/[index]*\.json$/, '')
Copy link
Copy Markdown
Contributor Author

@arunoda arunoda Dec 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change server/hot-reloader.js instead of this file. Maybe toRoute method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

? [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`])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, ideally, extensions should be changed on JsonPagesPlugin. Is it difficult ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. That's not hard. I think that makes sense. I'll do it.

export default read
export const cache = {}

read.cache = cache
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used on hot-reloader.js too. I think we need to fix it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

.on('error', (err) => {
if (err.code === 'ENOENT') {
res.statusCode = 404
res.end('Not Found')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this change is acceptable, but it'd be better if we can show the original 404.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Contributor

@nkzawa nkzawa Dec 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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])
Copy link
Copy Markdown
Contributor

@nkzawa nkzawa Dec 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Removed.

server/render.js Outdated
}

const gzipPath = `${path}.gz`
const exists = await fs.exists(gzipPath)
Copy link
Copy Markdown
Contributor

@nkzawa nkzawa Dec 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a deprecated API.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah! Seems like I need to read along the Node.js API again :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nkzawa Check now.
I figured, it's safe for us to use fs.access

@nkzawa
Copy link
Copy Markdown
Contributor

nkzawa commented Dec 31, 2016

👍 amazing

@nkzawa nkzawa merged commit 165924b into vercel:master Dec 31, 2016
@arunoda arunoda deleted the gzip-on-json-pages branch December 31, 2016 13:04
compiler.plugin('after-compile', (compilation, callback) => {
const pages = Object
.keys(compilation.assets)
.filter((filename) => /^bundles\/pages.*\.js$/.test(filename))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @msand for figuring this out.

@lock lock bot locked as resolved and limited conversation to collaborators Jan 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants