diff --git a/.babelrc.js b/.babelrc.js index 666c1a0efb70a..4eb42997a778d 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -6,10 +6,8 @@ if (process.env.NODE_ENV !== `test`) { ignore.push(`**/__tests__`) } -const presetAbsPath = require(`path`).join(__dirname, '.babel-preset.js') - module.exports = { sourceMaps: true, - presets: [presetAbsPath], + presets: ["babel-preset-gatsby-package"], ignore, } diff --git a/.circleci/config.yml b/.circleci/config.yml index da3aa0d5d9de8..731f713bc9d93 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,38 +1,34 @@ -aliases: - node6: &node6 - docker: - - image: circleci/node:6 - - node8: &node8 - docker: - - image: circleci/node:8 - - node10: &node10 +executors: + node: + parameters: + image: + type: string + default: "10" docker: - - image: circleci/node:10 + - image: circleci/node:<< parameters.image >> - node10_browsers: &node10_browsers +aliases: + e2e-executor: &e2e-executor docker: - - image: circleci/node:10-browsers + - image: cypress/browsers:chrome69 - restore_node_modules: &restore_node_modules + restore_cache: &restore_cache restore_cache: name: Restore node_modules cache keys: - - node-modules-{{ checksum "yarn.lock" }} + - yarn-cypress-cache-{{ checksum "yarn.lock" }} install_node_modules: &install_node_modules run: name: Install node modules - command: | - yarn + command: yarn --frozen-lockfile - persist_node_modules: &persist_node_modules + persist_cache: &persist_cache save_cache: name: Save node modules cache - key: node-modules-{{ checksum "yarn.lock" }} + key: yarn-cypress-cache-{{ checksum "yarn.lock" }} paths: - - node_modules + - ~/.cache attach_to_bootstrap: &attach_to_bootstrap attach_workspace: @@ -44,108 +40,126 @@ aliases: ignore: - master + ignore_docs: &ignore_docs + filters: + branches: + ignore: + - /docs.+/ + - /blog.+/ + test_template: &test_template steps: - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*" - - <<: *restore_node_modules + - run: ./scripts/assert-changed-files.sh "packages/*|.circleci/*" + - <<: *restore_cache - <<: *install_node_modules - - <<: *persist_node_modules + - <<: *persist_cache - <<: *attach_to_bootstrap - run: yarn jest -w 1 - integration_test_workflow: &integration_test_workflow - <<: *ignore_master + e2e-test-workflow: &e2e-test-workflow + filters: + branches: + ignore: + - master + - /docs.+/ + - /blog.+/ requires: - bootstrap -version: 2 +commands: + e2e-test: + parameters: + trigger_pattern: + type: string + default: "packages/*|.circleci/*" + test_path: + type: string + steps: + - checkout + - run: ./scripts/assert-changed-files.sh "<< parameters.trigger_pattern >>|<< parameters.test_path >>/*" + - <<: *restore_cache + - <<: *install_node_modules + - <<: *persist_cache + - <<: *attach_to_bootstrap + - run: ./scripts/e2e-test.sh "<< parameters.test_path >>" + +version: 2.1 jobs: bootstrap: - <<: *node10 + executor: node steps: - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*" - - <<: *restore_node_modules + - run: ./scripts/assert-changed-files.sh "packages/*|(e2e|integration)-tests/*|.circleci/*" + - <<: *restore_cache - <<: *install_node_modules - - <<: *persist_node_modules + - <<: *persist_cache - run: yarn bootstrap - persist_to_workspace: root: packages paths: - - '*' + - "*" lint: - <<: *node10 + executor: node steps: - checkout - - <<: *restore_node_modules + - <<: *restore_cache - <<: *install_node_modules - - <<: *persist_node_modules + - <<: *persist_cache - run: yarn lint unit_tests_node6: - <<: *node6 + executor: + name: node + image: "6" <<: *test_template unit_tests_node8: - <<: *node8 + executor: + name: node + image: "8" <<: *test_template unit_tests_node10: - <<: *node10 + executor: node <<: *test_template integration_tests: - <<: *node10 + executor: node steps: - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*" - - <<: *restore_node_modules + - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*|.circleci/*" + - <<: *restore_cache - <<: *install_node_modules - - <<: *persist_node_modules + - <<: *persist_cache + - <<: *attach_to_bootstrap - run: yarn test:integration e2e_tests_gatsbygram: - <<: *node10_browsers + <<: *e2e-executor steps: - - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*|examples/gatsbygram/*" - - <<: *restore_node_modules - - <<: *install_node_modules - - <<: *attach_to_bootstrap - - run: ./scripts/integration-test.sh examples/gatsbygram + - e2e-test: + test_path: examples/gatsbygram e2e_tests_path-prefix: - <<: *node10_browsers + <<: *e2e-executor steps: - - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*" - - <<: *restore_node_modules - - <<: *install_node_modules - - <<: *attach_to_bootstrap - - run: ./scripts/integration-test.sh integration-tests/path-prefix - + - e2e-test: + test_path: e2e-tests/path-prefix + e2e_tests_gatsby-image: - <<: *node10_browsers + <<: *e2e-executor steps: - - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*" - - <<: *restore_node_modules - - <<: *install_node_modules - - <<: *attach_to_bootstrap - - run: ./scripts/integration-test.sh integration-tests/gatsby-image - + - e2e-test: + test_path: e2e-tests/gatsby-image + e2e_tests_runtime: - <<: *node10_browsers + <<: *e2e-executor steps: - - checkout - - run: ./scripts/assert-changed-files.sh "packages/*|integration-tests/*" - - <<: *restore_node_modules - - <<: *install_node_modules - - <<: *attach_to_bootstrap - - run: ./scripts/integration-test.sh integration-tests/production-runtime + - e2e-test: + test_path: e2e-tests/production-runtime workflows: version: 2 @@ -154,20 +168,24 @@ workflows: - bootstrap - lint - unit_tests_node6: + <<: *ignore_docs requires: - bootstrap - unit_tests_node8: + <<: *ignore_docs requires: - bootstrap - unit_tests_node10: + <<: *ignore_docs requires: - bootstrap - - integration_tests + - integration_tests: + <<: *ignore_docs - e2e_tests_gatsbygram: - <<: *integration_test_workflow + <<: *e2e-test-workflow - e2e_tests_path-prefix: - <<: *integration_test_workflow + <<: *e2e-test-workflow - e2e_tests_gatsby-image: - <<: *integration_test_workflow + <<: *e2e-test-workflow - e2e_tests_runtime: - <<: *integration_test_workflow + <<: *e2e-test-workflow diff --git a/.editorconfig b/.editorconfig index 301b03d34efc2..ae10a5cce3b26 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,18 +2,9 @@ root = true [*] -indent_style = space -indent_size = 2 -end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[{*.json}] -indent_style = space -indent_size = 4 - -# Matches the exact package.json, or *rc -[{package.json,*.yml,*rc}] -indent_style = space +end_of_line = lf indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.eslintrc.json b/.eslintrc.json index a049b127e7747..4efa02222c841 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,7 +9,7 @@ "prettier/flowtype", "prettier/react" ], - "plugins": ["flowtype", "react"], + "plugins": ["flowtype", "prettier", "react"], "parserOptions": { "ecmaVersion": 2016, "sourceType": "module", @@ -27,36 +27,22 @@ "spyOn": true }, "rules": { - "no-console": "off", - "no-inner-declarations": "off", - "valid-jsdoc": "off", - "require-jsdoc": "off", - "quotes": ["error", "backtick"], - "consistent-return": ["error"], "arrow-body-style": [ "error", "as-needed", { "requireReturnForObjectLiteral": true } ], - "jsx-quotes": ["error", "prefer-double"], - "semi": ["error", "never"], - "object-curly-spacing": ["error", "always"], - "comma-dangle": [ - "error", - { - "arrays": "always-multiline", - "objects": "always-multiline", - "imports": "always-multiline", - "exports": "always-multiline", - "functions": "ignore" - } - ], - "react/prop-types": [ - "error", - { - "ignore": ["children"] - } - ] + "consistent-return": ["error"], + "no-console": "off", + "no-inner-declarations": "off", + "prettier/prettier": "error", + "quotes": ["error", "backtick"], + "react/display-name": "off", + "react/jsx-key": "warn", + "react/no-unescaped-entities": "warn", + "react/prop-types": "off", + "require-jsdoc": "off", + "valid-jsdoc": "off" }, "overrides": [ { @@ -71,6 +57,18 @@ "___loader": false, "___emitter": false } + }, + { + "files": ["**/cypress/integration/**/*", "**/cypress/support/**/*"], + "globals": { + "cy": false, + "Cypress": false + } + } + ], + "settings": { + "react": { + "version": "16.4.2" } - ] + } } diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000..a0e422d6c6037 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +**/*.js.snap text eol=lf +**/__testfixtures__/** text eol=lf +**/__tests__/fixtures/** text eol=lf +**/*.md text eol=lf \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0d1a73256da08..4b62aa84598b6 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,6 @@ Belongs in the docs (to make sure we don’t have to maintain docs about core dependencies and third-party software, we will focus on linking to their docs as much as possible) + +> **No** --> Belongs in blog, marketing, Twitter, podcast, starter library, plugin library, etc. + +2. Helps further something on the [developer journey](https://pronovix.com/blog/analyzing-api-docs-and-dx-patterns-best-banking-developer-portals): + + - Discover + - Evaluate + - Get Started + - Implement & Troubleshoot + - Celebrate & Share + - Contribute & Maintain + +> **Yes** --> Belongs in the docs + +> **No** --> Does not belong in the docs + +## Handling proposed doc changes + +### Someone wants to create a new doc + +Does doc already exist? + +> **Yes** --> Is there a discovery problem? If so, solve it + +> **No** --> move ahead + +Is there a demand to create the doc? + +> **Yes** --> move ahead + +> **No** --> don't create it + +Does the doc qualify to be in the /docs/? + +> **Yes** --> Create it + +> **No** --> Don't create it + +### Someone wants to create new categories in the docs sidebar + +Is there a category that the doc(s) could fit in that has more than 5-7 docs in it? + +> **Yes** --> Put in existing category + +> **No** --> Move on + +Would the new category have more than 2 docs in it? + +> **Yes** --> Create new category + +> **No** --> consider waiting to create the category until there is more than 2 docs + +### Someone wants to reorder the categories in the sidebar or shift docs to new categories + +Is there evidence that the reorganization would help further one of the steps on the developer journey? + +> **Yes** --> Reorder them and do usability testing to measure the value of the change + +> **No** --> Don't reorder the categories + +## Naming criteria + +Names categories in the .org site should: + +- be SEO-friendly (common google search term, easy-to-remember URL that is not likely to change anytime soon) +- communicate a core concept of Gatsby (TBD) and/or a core value (TBD) +- be a noun, like "plugins, styling, guides, core concepts" etc. + +Names for guides, tutorial sections, and sub-headings in the .org site should: + +- be SEO friendly (common google search term, easy-to-remember URL that is not likely to change anytime soon) +- nearly always start with an -ing verb, like "adding", since all tasks are action-oriented. + +## Thanks and keep Hacktoberfesting with Gatsby + +It’s been incredible to see how many hard-working contributors have gotten PR’s merged with us so far! Don't forget to check out [how to participate in Gatsby Hacktoberfest!](/blog/2018-10-09-hacktoberfest-kickoff/) + +And don’t forget to also read the [Docs Decision Tree RFC](https://github.com/gatsbyjs/rfcs/pull/14) and leave your comments before October 31st, when the commenting period will be closed. diff --git a/docs/blog/2018-10-15-beyond-static-intro/images/dynamic.jpg b/docs/blog/2018-10-15-beyond-static-intro/images/dynamic.jpg new file mode 100644 index 0000000000000..498bdf59fedaa Binary files /dev/null and b/docs/blog/2018-10-15-beyond-static-intro/images/dynamic.jpg differ diff --git a/docs/blog/2018-10-15-beyond-static-intro/index.md b/docs/blog/2018-10-15-beyond-static-intro/index.md new file mode 100644 index 0000000000000..32e787a8e3afa --- /dev/null +++ b/docs/blog/2018-10-15-beyond-static-intro/index.md @@ -0,0 +1,61 @@ +--- +title: "Beyond Static: Building Dynamic Apps with Gatsby" +date: 2018-10-15 +author: Dustin Schau +image: images/dynamic.jpg +showImageInArticle: false +tags: ["apps", "beyond static", "webinar"] +--- + +We hear it regularly. Gatsby is for static sites, Next.js (or similar) is for when your data changes regularly and/or you need an "app." This raises a question... what actually _is_ an app? + +If this question interests you, consider attending [the upcoming webinar][webinar] where we'll focus on shedding some light on this very question as well as talk about how to build dynamic web apps with Gatsby. + +Until then, I’d like to offer some brief teasers of some of the content we’ll be discussing during the webinar and some introductory information in _how_ Gatsby enables app development. + +> My first impression of Gatsby is that it is more of a static site generator which I interpret as being aimed at content or marketing websites and not as focused on web apps. That is a complete assumption so please correct me if I am wrong. +> +> - [Triptcip][reddit-thread] + +## What is an app? + +It's surprisingly challenging to define what separates an app from a static site. + +- Authentication? +- Reacting to remote data changes? +- A shopping cart? + +It's surprisingly murky where that line is drawn and why exactly many seem to clearly delineate the two _separate_ concepts. + +In fact, I contend that the line between these two concepts is extremely blurry. There isn't some magic percentage threshold that, when crossed, indicates that a static site is now an application. Nor is the inverse true, that an "app" is somehow static because some percentage of its content never or rarely changes. + +From this perspective, it's fair to consider dynamic content as the key determinant between static sites and apps. The more dynamic content an application has, the more app-like that application feels. From this basis, Gatsby is an excellent choice because it enables dynamic functionality just as easily as it enables static site generation. + +## How does Gatsby enable app functionality? + +Gatsby is great for static sites and for truly maximizing performance, while also maintaining a great developer experience and enabling fast feature development with tools developers actually _want_ to use. React, GraphQL, headless CMSes, and the list goes on and on. We enable these, and more, in an easy-to-use package that gets blazing-fast performance, by _default_. It's possible you've heard us talk about these things before 😅 We've honed in on this message and initially focused on this core functionality of building static sites. However, that's only one side of the coin. Gatsby's flexibility and one of its **core** ideas enable building apps on top of this solid static base. + +### Hydration + +One of the central ideas of Gatsby is that we statically generate our HTML content--using React DOM server-side APIs. A less-often illustrated feature is that this static HTML content can then be _enhanced_ with client-side JavaScript via React hydration. The general approach is as follows: + +1. Build and render static HTML, creating content and pages with data injected at build time +1. Invoke [ReactDOM.hydrate method][hydrate] to pick up just where we left our static HTML +1. Transfer rendering to the [React reconciler][reconciler] + +It's this last phase that bridges the gap between static sites and full-fledged applications. In this phase you can make data calls, authenticate users, and perform all the app-like functionality you desire. + +It's really that easy. + +## Use cases + +Gatsby enables these hooks to deliver app-like functionality, just as it does for static site generation. However, it's not as clear when it makes sense to reach for something purely server rendered (Next.js, Nuxt, etc.) or a hybrid approach, like we offer in Gatsby. In the webinar, I'll go over a number of examples of various types of web apps, including e-commerce apps, apps which utilize authentication, and apps that connect to a remote data source (e.g. a GraphQL API), among others! You'll leave having a clear mental model of the types of apps that **you** can build with Gatsby. + +## Wrap Up + +If these briefly described topics and use cases sound interesting to you then please consider [signing up for the Webinar][webinar]. I can't wait to share some practical advice, excellent tooling, and a live demo to show you how you can #BuildWithGatsby in more ways than _just_ static. I hope to see you there! + +[reddit-thread]: https://www.reddit.com/r/reactjs/comments/992n2r/next_vs_gatsby/?st=jn6cojmr&sh=1a53fac1 +[webinar]: https://www.gatsbyjs.com/build-web-apps-webinar +[hydrate]: https://reactjs.org/docs/react-dom.html#hydrate +[reconciler]: https://reactjs.org/docs/reconciliation.html diff --git a/docs/blog/2018-10-16-why-mobile-performance-is-crucial/index.md b/docs/blog/2018-10-16-why-mobile-performance-is-crucial/index.md new file mode 100644 index 0000000000000..cb6a47cc3d678 --- /dev/null +++ b/docs/blog/2018-10-16-why-mobile-performance-is-crucial/index.md @@ -0,0 +1,164 @@ +--- +title: "Journey to the Content Mesh Part 4: Why Mobile Performance Is Crucial" +author: "Sam Bhagwat" +"date": 2018-10-16 +tags: ["content-mesh"] +--- + +_This is Part 4 of a series. Part 1 is_ [The Journey to a Content Mesh](/blog/2018-10-04-journey-to-the-content-mesh)_; Part 2 is_ [Unbundling of the CMS](/blog/2018-10-10-unbundling-of-the-cms)_; Part 3 is_ [The Rise of Modern Web Development](/blog/2018-10-11-rise-of-modern-web-development). + +Mobile traffic now makes up over half of all site visits, and more than half of mobile site visits are abandoned if a page takes [over 3 seconds to load](https://www.thinkwithgoogle.com/data-gallery/detail/mobile-site-abandonment-three-second-load/). + +With the Fortune 500 spending millions of marketing dollars on marketing initiatives aimed at driving traffic to their site, the business impact of bouncing visitors is clear -- [every 100ms of latency costs 1% of sales.](https://www.digitalrealty.com/blog/the-cost-of-latency/) + +Unfortunately, in practice, great performance is surprisingly hard to achieve -- average page load times _haven’t improved_ over several years of increasing connection speed. + +Why is that? Increased site complexity often distributes bottlenecks across multiple code points and teams of stakeholders. While performance checklists exist, they’ve ballooned to 40+ items -- making them costly and time-consuming for teams to implement. + +As Gatsby's co-founder Kyle Mathews likes to say (paraphrasing Tolstoy): + +> "All fast websites are alike, but all slow websites are slow in different ways." + +Ultimately, we’ll argue, performance must be solved _at the framework level_ -- that is, in the content mesh. + +## The rise of smartphone usage + +Between 2014 and 2017, mobile usage (including tablets) rose from 20% of site visits to 50% of site visits. + + + + +Source: [StatCounter](http://gs.statcounter.com/platform-market-share/desktop-mobile-tablet/worldwide/2011) + +When smartphones were first created, the first key challenge of website teams was to offer a responsive version of their site that worked on mobile devices _at all._ + +As mobile has grown to half of internet traffic, the key challenge has shifted to performance. + +## Faster connections haven’t translated to faster sites + +While average phone connection speed, as well as processing power, has increased over the last several years, sites haven’t gotten faster. In fact, load times **have increased**. + +Data from the HTTPArchive shows how long it's taken for the average page on the Internet to completely load all content (including images, script files, CSS files, etc.): + +
+ +
+ Web performance over time +
+
+ +Source: [HTTPArchive](https://httparchive.org/reports/loading-speed?start=2014_02_01&end=latest&view=list#ol) + +Why is that? + +Connection speeds for mobile device have increased, while Moore's Law has made devices faster. However, these speed dividends have been eaten up by two things. + +First, **[heavier page weights](https://www.keycdn.com/support/the-growth-of-web-page-size/)**. + +This has generally driven by increased page complexity driven by increased user expectations. + +Second, the **growing complexity of websites**. Non-critical images, CSS, JS libraries, and 3rd party tracking software will often unintentionally end up on the critical path to page load: + +- A marketing analyst drops a `"`; -exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"
div3
div2
div1
"`; +exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"
div3
div2
div1
"`; exports[`static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"
div3
div2
div1
"`; diff --git a/packages/gatsby/cache-dir/__tests__/error-overlay-handler.js b/packages/gatsby/cache-dir/__tests__/error-overlay-handler.js new file mode 100644 index 0000000000000..088793742e9e4 --- /dev/null +++ b/packages/gatsby/cache-dir/__tests__/error-overlay-handler.js @@ -0,0 +1,59 @@ +import "@babel/polyfill" +const { + reportError, + clearError, + errorMap, +} = require(`../error-overlay-handler`) + +import * as ErrorOverlay from "react-error-overlay" + +jest.mock(`react-error-overlay`, () => { + return { + reportBuildError: jest.fn(), + dismissBuildError: jest.fn(), + startReportingRuntimeErrors: jest.fn(), + setEditorHandler: jest.fn(), + } +}) + +beforeEach(() => { + ErrorOverlay.reportBuildError.mockClear() + ErrorOverlay.dismissBuildError.mockClear() +}) + +describe(`errorOverlayHandler`, () => { + describe(`clearError()`, () => { + beforeEach(() => { + reportError(`foo`, `error`) + reportError(`bar`, `error`) + }) + afterAll(() => { + clearError(`foo`) + clearError(`bar`) + }) + it(`should clear specific error type`, () => { + expect(Object.keys(errorMap)).toHaveLength(2) + clearError(`foo`) + expect(Object.keys(errorMap)).toHaveLength(1) + expect(ErrorOverlay.dismissBuildError).not.toHaveBeenCalled() + }) + + it(`should call ErrorOverlay to dismiss build errors`, () => { + clearError(`foo`) + clearError(`bar`) + expect(ErrorOverlay.dismissBuildError).toHaveBeenCalled() + }) + }) + describe(`reportErrorOverlay()`, () => { + it(`should not add error if it's empty and not call ErrorOverlay`, () => { + reportError(`foo`, null) + expect(Object.keys(errorMap)).toHaveLength(0) + expect(ErrorOverlay.reportBuildError).not.toHaveBeenCalled() + }) + it(`should add error if it has a truthy value and call ErrorOverlay`, () => { + reportError(`foo`, `bar`) + expect(Object.keys(errorMap)).toHaveLength(1) + expect(ErrorOverlay.reportBuildError).toHaveBeenCalled() + }) + }) +}) diff --git a/packages/gatsby/cache-dir/__tests__/minimal-config.js b/packages/gatsby/cache-dir/__tests__/minimal-config.js index 0dc919641e741..7f7f7c9d59529 100644 --- a/packages/gatsby/cache-dir/__tests__/minimal-config.js +++ b/packages/gatsby/cache-dir/__tests__/minimal-config.js @@ -1,30 +1,36 @@ const path = require(`path`) const child = require(`child_process`) -it(`Builds cache-dir with minimal config`, done => { - const args = [ - require.resolve(`@babel/cli/bin/babel.js`), - path.join(__dirname, `..`), - `--config-file`, - path.join(__dirname, `.babelrc`), - ] +it( + `Builds cache-dir with minimal config`, + done => { + const args = [ + require.resolve(`@babel/cli/bin/babel.js`), + path.join(__dirname, `..`), + `--config-file`, + path.join(__dirname, `.babelrc`), + `--ignore`, + `**/__tests__`, + ] - const spawn = child.spawn(process.execPath, args) + const spawn = child.spawn(process.execPath, args) - let stderr = `` - let stdout = `` + let stderr = `` + let stdout = `` - spawn.stderr.on(`data`, function (chunk) { - stderr += chunk - }) + spawn.stderr.on(`data`, function(chunk) { + stderr += chunk + }) - spawn.stdout.on(`data`, function (chunk) { - stdout += chunk - }) + spawn.stdout.on(`data`, function(chunk) { + stdout += chunk + }) - spawn.on(`close`, function () { - expect(stderr).toEqual(``) - expect(stdout).not.toEqual(``) - done() - }) -}, 30000) + spawn.on(`close`, function() { + expect(stderr).toEqual(``) + expect(stdout).not.toEqual(``) + done() + }) + }, + 30000 +) diff --git a/packages/gatsby/cache-dir/__tests__/static-entry.js b/packages/gatsby/cache-dir/__tests__/static-entry.js index 785247fb23692..03d857d15a1de 100644 --- a/packages/gatsby/cache-dir/__tests__/static-entry.js +++ b/packages/gatsby/cache-dir/__tests__/static-entry.js @@ -2,9 +2,11 @@ import React from "react" import DevelopStaticEntry from "../develop-static-entry" jest.mock(`fs`) -jest.mock(`gatsby/package.json`, () => ({ - version: '2.0.0' -})); +jest.mock(`gatsby/package.json`, () => { + return { + version: `2.0.0`, + } +}) jest.mock( `../sync-requires`, diff --git a/packages/gatsby/cache-dir/api-runner-browser.js b/packages/gatsby/cache-dir/api-runner-browser.js index b86a91ce3ca6c..036fee8278ec8 100644 --- a/packages/gatsby/cache-dir/api-runner-browser.js +++ b/packages/gatsby/cache-dir/api-runner-browser.js @@ -6,6 +6,17 @@ const { } = require(`./loader`).publicLoader exports.apiRunner = (api, args = {}, defaultReturn, argTransform) => { + // Hooks for cypress-gatsby's API handler + if (window.Cypress) { + if (window.___apiHandler) { + window.___apiHandler(api) + } else if (window.___resolvedAPIs) { + window.___resolvedAPIs.push(api) + } else { + window.___resolvedAPIs = [api] + } + } + let results = plugins.map(plugin => { if (!plugin.plugin[api]) { return undefined diff --git a/packages/gatsby/cache-dir/api-ssr-docs.js b/packages/gatsby/cache-dir/api-ssr-docs.js index 389c05c9eabeb..6890ea7150b75 100644 --- a/packages/gatsby/cache-dir/api-ssr-docs.js +++ b/packages/gatsby/cache-dir/api-ssr-docs.js @@ -142,6 +142,7 @@ exports.onPreRenderHTML = true * @param {object} $0 * @param {object} $0.element The "Page" React Element built by Gatsby. * @param {object} $0.props Props object used by page. + * @param {string} $0.pathname Path of page. * @example * import React from "react" * import Layout from "./src/components/Layout" diff --git a/packages/gatsby/cache-dir/app.js b/packages/gatsby/cache-dir/app.js index 74d4a0a788067..ec3d0c65ae416 100644 --- a/packages/gatsby/cache-dir/app.js +++ b/packages/gatsby/cache-dir/app.js @@ -1,16 +1,23 @@ import React from "react" import ReactDOM from "react-dom" import domReady from "domready" -import { hot } from "react-hot-loader" +import { hot, setConfig } from "react-hot-loader" import socketIo from "./socketIo" import emitter from "./emitter" import { apiRunner, apiRunnerAsync } from "./api-runner-browser" -import loader from "./loader" +import loader, { setApiRunnerForLoader } from "./loader" import syncRequires from "./sync-requires" import pages from "./pages.json" window.___emitter = emitter +setApiRunnerForLoader(apiRunner) + +// necessary for hot-reloading of react hooks +setConfig({ + ignoreSFC: true, + pureRender: true, +}) // Let the site/plugins run code very early. apiRunnerAsync(`onClientEntry`).then(() => { diff --git a/packages/gatsby/cache-dir/develop-static-entry.js b/packages/gatsby/cache-dir/develop-static-entry.js index 4d3a44d8c14b2..56be0d1d0fd55 100644 --- a/packages/gatsby/cache-dir/develop-static-entry.js +++ b/packages/gatsby/cache-dir/develop-static-entry.js @@ -101,6 +101,8 @@ export default (pagePath, callback) => { headComponents: headComponents.concat([