Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v2] Hulksmash build slowdowns on larger sites #6226

Merged
merged 32 commits into from
Jul 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ac4a874
Hulksmash slowdowns on larger sites
KyleAMathews Jun 29, 2018
cb33713
Switch more existsSync to use caching version
KyleAMathews Jun 30, 2018
253e353
Convert node reducer to use Map
KyleAMathews Jun 30, 2018
84c516a
Fix most lint errors
KyleAMathews Jun 30, 2018
b647bb1
Merge branch 'master' into speed-large-site
KyleAMathews Jul 3, 2018
266f5ae
Split writing page data json files into 999 folders to speed writes
KyleAMathews Jul 4, 2018
110b99e
Use forEach instead of reduce when prepping page data
KyleAMathews Jul 5, 2018
710d9d8
Profiled code and fixed hot functions
KyleAMathews Jul 6, 2018
b039a64
Merge remote-tracking branch 'origin/master' into speed-large-site
KyleAMathews Jul 6, 2018
6a8e9a0
WIP commit to dramatically speed up graphql queries
KyleAMathews Jul 7, 2018
044e7b6
Handle picking directory to write StaticQuery results
KyleAMathews Jul 9, 2018
f231e08
Speed up resolving queries when the query is querying a node by id
KyleAMathews Jul 9, 2018
0c43b29
Show pages rendered / second while building HTML
KyleAMathews Jul 10, 2018
109d691
Add sites for benchmarking
KyleAMathews Jul 10, 2018
272e6b0
Persist activity status at end and show queries/second for graphql
KyleAMathews Jul 10, 2018
19f6c3b
Restore creating SitePage nodes as no longer slow
KyleAMathews Jul 10, 2018
a46c207
Correct storing/using/deleting nodes
KyleAMathews Jul 10, 2018
fe4125b
Disable profiling
KyleAMathews Jul 10, 2018
d3a95a0
Remove extra dependencies
KyleAMathews Jul 10, 2018
d6eefc5
Format + fix linting
KyleAMathews Jul 10, 2018
b729410
remove console.log and unused profile
KyleAMathews Jul 11, 2018
34db11f
Remove another profile
KyleAMathews Jul 11, 2018
daf690f
Fix tests (hopefully)
KyleAMathews Jul 11, 2018
db319af
Merge remote-tracking branch 'origin/master' into speed-large-site
KyleAMathews Jul 11, 2018
d3acb9e
Check if nodes exists, sometimes a test fails otherwise
KyleAMathews Jul 11, 2018
145a34b
debugging...
KyleAMathews Jul 11, 2018
c85d41e
Work around...
KyleAMathews Jul 11, 2018
2cb28c7
Don't need to run bootstrap on tests as jest compiles code
KyleAMathews Jul 11, 2018
b7ebd8e
Lodash uses Object.entries which fails on node 6... :-"
KyleAMathews Jul 11, 2018
a4a1391
Ok, do need bootstrap to link packages
KyleAMathews Jul 11, 2018
aa47043
Try try again
KyleAMathews Jul 11, 2018
fa32e5d
Ugh, problem was Object.entries isn't in Node 6
KyleAMathews Jul 11, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions benchmarks/create-pages/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

.cache/
public
yarn-error.log
21 changes: 21 additions & 0 deletions benchmarks/create-pages/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 gatsbyjs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
5 changes: 5 additions & 0 deletions benchmarks/create-pages/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# createPages benchmark

Stress tests creating lots of tiny pages.

Defaults to building a site with 5k pages. Set the `NUM_PAGES` environment variable to change that e.g. `NUM_PAGES=25000 gatsby build`
18 changes: 18 additions & 0 deletions benchmarks/create-pages/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
let NUM_PAGES = 5000

if (process.env.NUM_PAGES) {
NUM_PAGES = process.env.NUM_PAGES
}

exports.createPages = ({ actions: { createPage } }) => {
var step
for (step = 0; step < NUM_PAGES; step++) {
createPage({
path: `/path/${step}/`,
component: require.resolve(`./src/templates/blank.js`),
context: {
id: step,
},
})
}
}
15 changes: 15 additions & 0 deletions benchmarks/create-pages/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "gatsby-starter-hello-world",
"description": "Gatsby hello world starter",
"license": "MIT",
"scripts": {
"develop": "gatsby develop",
"build": "gatsby build",
"serve": "gatsby serve"
},
"dependencies": {
"gatsby": "next",
"react": "^16.3.2",
"react-dom": "^16.3.2"
}
}
3 changes: 3 additions & 0 deletions benchmarks/create-pages/src/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import React from "react"

export default () => <div>Hello world!</div>
3 changes: 3 additions & 0 deletions benchmarks/create-pages/src/templates/blank.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import React from "react"

export default () => <div>Yo!</div>
62 changes: 62 additions & 0 deletions benchmarks/markdown/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

.cache/
public
yarn-error.log
21 changes: 21 additions & 0 deletions benchmarks/markdown/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 gatsbyjs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
5 changes: 5 additions & 0 deletions benchmarks/markdown/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Markdown benchmark

Stress tests creating lots of pages rendered from Markdown.

Defaults to building a site with 5k markdown pages. Set the `NUM_PAGES` environment variable to change that e.g. `NUM_PAGES=25000 gatsby build`
3 changes: 3 additions & 0 deletions benchmarks/markdown/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
plugins: [`gatsby-transformer-remark`],
};
36 changes: 36 additions & 0 deletions benchmarks/markdown/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
let NUM_PAGES = 5000

if (process.env.NUM_PAGES) {
NUM_PAGES = process.env.NUM_PAGES
}

exports.sourceNodes = ({ actions: { createNode } }) => {
// Create markdown nodes
let step
for (step = 0; step < NUM_PAGES; step++) {
createNode({
id: step.toString(),
parent: null,
children: [],
internal: {
type: `FakeMarkdown`,
mediaType: `text/markdown`,
content: `---\ntitle: "hi"\n---\nWhat up folks? This is _lit_\n\n##Page #${step}`,
contentDigest: step.toString(),
},
})
}
}

exports.createPages = ({ actions: { createPage } }) => {
let step
for (step = 0; step < NUM_PAGES; step++) {
createPage({
path: `/path/${step}/`,
component: require.resolve(`./src/templates/blank.js`),
context: {
id: step,
},
})
}
}
16 changes: 16 additions & 0 deletions benchmarks/markdown/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "gatsby-starter-hello-world",
"description": "Gatsby hello world starter",
"license": "MIT",
"scripts": {
"develop": "gatsby develop",
"build": "gatsby build",
"serve": "gatsby serve"
},
"dependencies": {
"gatsby": "next",
"gatsby-transformer-remark": "^2.1.1-beta.2",
"react": "^16.3.2",
"react-dom": "^16.3.2"
}
}
3 changes: 3 additions & 0 deletions benchmarks/markdown/src/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import React from "react"

export default () => <div>Hello world!</div>
25 changes: 25 additions & 0 deletions benchmarks/markdown/src/templates/blank.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react"
import { graphql } from "gatsby"

export default ({ data }) => {
const markdown = data.fakeMarkdown.childMarkdownRemark
return (
<div>
<h1>{markdown.frontmatter.title}</h1>
<div dangerouslySetInnerHTML={{ __html: markdown.html }} />
</div>
)
}

export const query = graphql`
query testing($id: String!) {
fakeMarkdown(id: { eq: $id }) {
childMarkdownRemark {
frontmatter {
title
}
html
}
}
}
`
1 change: 1 addition & 0 deletions packages/gatsby-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"core-js": "^2.5.0",
"envinfo": "^5.8.1",
"execa": "^0.8.0",
"fs-exists-cached": "^1.0.0",
"fs-extra": "^4.0.1",
"hosted-git-info": "^2.6.0",
"lodash": "^4.17.4",
Expand Down
4 changes: 2 additions & 2 deletions packages/gatsby-cli/src/create-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const path = require(`path`)
const resolveCwd = require(`resolve-cwd`)
const yargs = require(`yargs`)
const report = require(`./reporter`)
const fs = require(`fs`)
const envinfo = require(`envinfo`)
const existsSync = require(`fs-exists-cached`).sync

const DEFAULT_BROWSERS = [`>0.25%`, `not dead`]

Expand All @@ -19,7 +19,7 @@ function buildLocalCommands(cli, isLocalSite) {
const directory = path.resolve(`.`)

let siteInfo = { directory, browserslist: DEFAULT_BROWSERS }
const useYarn = fs.existsSync(path.join(directory, `yarn.lock`))
const useYarn = existsSync(path.join(directory, `yarn.lock`))
if (isLocalSite) {
const json = require(path.join(directory, `package.json`))
siteInfo.sitePackageJson = json
Expand Down
5 changes: 3 additions & 2 deletions packages/gatsby-cli/src/init-starter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const fs = require(`fs-extra`)
const sysPath = require(`path`)
const report = require(`./reporter`)
const url = require(`url`)
const existsSync = require(`fs-exists-cached`).sync

const spawn = (cmd: string) => {
const [file, ...args] = cmd.split(/\s+/)
Expand Down Expand Up @@ -49,7 +50,7 @@ const copy = async (starterPath: string, rootPath: string) => {
// 493 = parseInt('755', 8)
await fs.mkdirp(rootPath, { mode: 493 })

if (!fs.existsSync(starterPath)) {
if (!existsSync(starterPath)) {
throw new Error(`starter ${starterPath} doesn't exist`)
}

Expand Down Expand Up @@ -117,7 +118,7 @@ module.exports = async (starter: string, options: InitOptions = {}) => {
return
}

if (fs.existsSync(sysPath.join(rootPath, `package.json`))) {
if (existsSync(sysPath.join(rootPath, `package.json`))) {
report.panic(`Directory ${rootPath} is already an npm project`)
return
}
Expand Down
10 changes: 9 additions & 1 deletion packages/gatsby-cli/src/reporter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ module.exports = Object.assign(reporter, {
activityTimer(name) {
const spinner = reporter.activity()
const start = process.hrtime()
let status

const elapsedTime = () => {
var elapsed = process.hrtime(start)
Expand All @@ -85,8 +86,15 @@ module.exports = Object.assign(reporter, {
start: () => {
spinner.tick(name)
},
setStatus: s => {
status = s
spinner.tick(`${name} — ${status}`)
},
end: () => {
reporter.success(`${name} — ${elapsedTime()}`)
const str = status
? `${name} — ${elapsedTime()} — ${status}`
: `${name} — ${elapsedTime()}`
reporter.success(str)
spinner.end()
},
}
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-plugin-netlify/src/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ exports.onPostBuild = async ({ store, pathPrefix }, userPluginOptions) => {
let rewrites = []
if (pluginOptions.generateMatchPathRewrites) {
const { pages } = store.getState()
rewrites = pages
rewrites = Array.from(pages.values())
Copy link
Contributor

Choose a reason for hiding this comment

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

You should be able to gain some more speed using reduce:

rewrites = Array.from(pages.values())
	.reduce((acc, page) => {
  	if (page.matchPath && page.matchPath !== page.path) {
    	acc.push({
        fromPath: page.matchPath,
        toPath: page.path,
      })
    }
    
    return acc;
  }, [])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would reducing be faster than filtering?

Copy link
Contributor

Choose a reason for hiding this comment

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

You get to avoid using map to iterate through the generated array from the filter. With reduce you generate the end result in a single iteration.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm yeah. Generally there'll only a handful of pages w/ matchPath so making the change should make a negligible difference 🤷‍♂️

That being said, if you'd like to make the PR, happy to take it! Thanks for reading through the PR!

.filter(page => page.matchPath && page.matchPath !== page.path)
.map(page => {
return {
Expand Down
Loading