diff --git a/e2e-tests/development-runtime/cypress/integration/functionality/queries-in-packages.js b/e2e-tests/development-runtime/cypress/integration/functionality/queries-in-packages.js
new file mode 100644
index 0000000000000..efcf5a6c588cd
--- /dev/null
+++ b/e2e-tests/development-runtime/cypress/integration/functionality/queries-in-packages.js
@@ -0,0 +1,14 @@
+describe(`queries in packages`, () => {
+ beforeEach(() => {
+ cy.visit(`/queries-in-packages`).waitForRouteChange()
+ })
+
+ it(`Should extract and run query from gatsby component`, () => {
+ // we are using `gatsby-seo` package which sets
+ // window's title to title passed as prop followed by siteMetadata.title
+ cy.title().should(
+ `eq`,
+ `Testing queries in packages | Gatsby Default Starter`
+ )
+ })
+})
diff --git a/e2e-tests/development-runtime/package.json b/e2e-tests/development-runtime/package.json
index 3c2889fd16348..967c4175895b2 100644
--- a/e2e-tests/development-runtime/package.json
+++ b/e2e-tests/development-runtime/package.json
@@ -10,6 +10,7 @@
"gatsby-plugin-offline": "^2.1.0",
"gatsby-plugin-react-helmet": "^3.0.6",
"gatsby-plugin-sharp": "^2.0.37",
+ "gatsby-seo": "^0.1.0",
"gatsby-source-filesystem": "^2.0.33",
"gatsby-transformer-remark": "^2.3.12",
"gatsby-transformer-sharp": "^2.1.19",
@@ -25,11 +26,11 @@
"license": "MIT",
"scripts": {
"build": "gatsby build",
- "develop": "cross-env ENABLE_GATSBY_REFRESH_ENDPOINT=true gatsby develop",
+ "develop": "cross-env CYPRESS_SUPPORT=y ENABLE_GATSBY_REFRESH_ENDPOINT=true gatsby develop",
"serve": "gatsby serve",
"start": "npm run develop",
"format": "prettier --write \"src/**/*.js\"",
- "test": "CYPRESS_SUPPORT=y npm run start-server-and-test || (npm run reset && exit 1)",
+ "test": "npm run start-server-and-test || (npm run reset && exit 1)",
"posttest": "npm run reset",
"reset": "node scripts/reset.js",
"reset:preview": "node plugins/gatsby-source-fake-data/reset.js && npm run update:preview",
diff --git a/e2e-tests/development-runtime/src/pages/queries-in-packages.js b/e2e-tests/development-runtime/src/pages/queries-in-packages.js
new file mode 100644
index 0000000000000..dde20480b38fe
--- /dev/null
+++ b/e2e-tests/development-runtime/src/pages/queries-in-packages.js
@@ -0,0 +1,13 @@
+import React from "react"
+import SEO from "gatsby-seo"
+
+import Layout from "../components/layout"
+
+export default () => (
+
+
+
+)
diff --git a/e2e-tests/production-runtime/cypress/integration/queries-in-packages.js b/e2e-tests/production-runtime/cypress/integration/queries-in-packages.js
new file mode 100644
index 0000000000000..efcf5a6c588cd
--- /dev/null
+++ b/e2e-tests/production-runtime/cypress/integration/queries-in-packages.js
@@ -0,0 +1,14 @@
+describe(`queries in packages`, () => {
+ beforeEach(() => {
+ cy.visit(`/queries-in-packages`).waitForRouteChange()
+ })
+
+ it(`Should extract and run query from gatsby component`, () => {
+ // we are using `gatsby-seo` package which sets
+ // window's title to title passed as prop followed by siteMetadata.title
+ cy.title().should(
+ `eq`,
+ `Testing queries in packages | Gatsby Default Starter`
+ )
+ })
+})
diff --git a/e2e-tests/production-runtime/gatsby-config.js b/e2e-tests/production-runtime/gatsby-config.js
index eebaa291e6bb4..2ebb93056e601 100644
--- a/e2e-tests/production-runtime/gatsby-config.js
+++ b/e2e-tests/production-runtime/gatsby-config.js
@@ -1,10 +1,8 @@
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
- author: {
- name: `Kyle Mathews`,
- bio: `lives and works in San Francisco building useful things`,
- },
+ author: `Kyle Mathews`,
+ description: `This is site for production runtime e2e tests`,
},
plugins: [
`gatsby-plugin-react-helmet`,
diff --git a/e2e-tests/production-runtime/package.json b/e2e-tests/production-runtime/package.json
index 89c90bca24b6b..b05f9cd4f7ef7 100644
--- a/e2e-tests/production-runtime/package.json
+++ b/e2e-tests/production-runtime/package.json
@@ -9,6 +9,7 @@
"gatsby-plugin-manifest": "^2.0.17",
"gatsby-plugin-offline": "^2.0.23",
"gatsby-plugin-react-helmet": "^3.0.6",
+ "gatsby-seo": "^0.1.0",
"glob": "^7.1.3",
"react": "^16.8.0",
"react-dom": "^16.8.0",
diff --git a/e2e-tests/production-runtime/src/components/bio.js b/e2e-tests/production-runtime/src/components/bio.js
index 50604f3b3e3ee..4fa3013a866d6 100644
--- a/e2e-tests/production-runtime/src/components/bio.js
+++ b/e2e-tests/production-runtime/src/components/bio.js
@@ -7,11 +7,7 @@ function Bio() {
query={bioQuery}
render={data => (
-
- A site by {data.site.siteMetadata.author.name} who
- {` `}
- {data.site.siteMetadata.author.bio}
-
+
A site by {data.site.siteMetadata.author}
)}
/>
@@ -22,10 +18,7 @@ export const bioQuery = graphql`
{
site {
siteMetadata {
- author {
- bio
- name
- }
+ author
}
}
}
diff --git a/e2e-tests/production-runtime/src/components/static-query/exported-variable-query.js b/e2e-tests/production-runtime/src/components/static-query/exported-variable-query.js
index 449cd05204bf3..ab8e7d94bd186 100644
--- a/e2e-tests/production-runtime/src/components/static-query/exported-variable-query.js
+++ b/e2e-tests/production-runtime/src/components/static-query/exported-variable-query.js
@@ -5,7 +5,7 @@ function ExportedVariable(props) {
return (
{data.site.siteMetadata.author.name}
}
+ render={data => {data.site.siteMetadata.author}
}
/>
)
}
@@ -14,9 +14,7 @@ export const nameQuery = graphql`
{
site {
siteMetadata {
- author {
- name
- }
+ author
}
}
}
diff --git a/e2e-tests/production-runtime/src/pages/queries-in-packages.js b/e2e-tests/production-runtime/src/pages/queries-in-packages.js
new file mode 100644
index 0000000000000..bd32b0c8083b5
--- /dev/null
+++ b/e2e-tests/production-runtime/src/pages/queries-in-packages.js
@@ -0,0 +1,13 @@
+import React from 'react'
+import SEO from 'gatsby-seo'
+
+import Layout from '../components/layout'
+
+export default () => (
+
+
+
+)
diff --git a/packages/gatsby/src/query/query-compiler.js b/packages/gatsby/src/query/query-compiler.js
index 64294c556c69d..d8d8a2d1a9da3 100644
--- a/packages/gatsby/src/query/query-compiler.js
+++ b/packages/gatsby/src/query/query-compiler.js
@@ -10,6 +10,7 @@ import RelayParser from "@gatsbyjs/relay-compiler/lib/RelayParser"
import ASTConvert from "@gatsbyjs/relay-compiler/lib/ASTConvert"
import GraphQLCompilerContext from "@gatsbyjs/relay-compiler/lib/GraphQLCompilerContext"
import filterContextForNode from "@gatsbyjs/relay-compiler/lib/filterContextForNode"
+import getGatsbyDependents from "../utils/gatsby-dependents"
const _ = require(`lodash`)
import { store } from "../redux"
@@ -102,11 +103,14 @@ class Runner {
async parseEverything() {
const filesRegex = path.join(`/**`, `*.+(t|j)s?(x)`)
+ const modulesThatUseGatsby = await getGatsbyDependents()
+
let files = [
path.join(this.base, `src`),
path.join(this.base, `.cache`, `fragments`),
]
.concat(this.additional.map(additional => path.join(additional, `src`)))
+ .concat(modulesThatUseGatsby.map(module => module.path))
.reduce(
(merged, folderPath) =>
merged.concat(
diff --git a/packages/gatsby/src/utils/__tests__/__snapshots__/webpack-utils.js.snap b/packages/gatsby/src/utils/__tests__/__snapshots__/webpack-utils.js.snap
index eb3793f597a77..ea89eecf03346 100644
--- a/packages/gatsby/src/utils/__tests__/__snapshots__/webpack-utils.js.snap
+++ b/packages/gatsby/src/utils/__tests__/__snapshots__/webpack-utils.js.snap
@@ -1,22 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`webpack utils js returns default values without any options 1`] = `
-Object {
- "exclude": /\\(node_modules\\|bower_components\\)/,
- "test": /\\\\\\.\\(js\\|mjs\\|jsx\\)\\$/,
- "type": "javascript/auto",
- "use": Array [
- Object {
- "loader": "/packages/gatsby/src/utils/babel-loader.js",
- "options": Object {},
- },
- ],
-}
-`;
-
-exports[`webpack utils js returns default values without any options 2`] = `
+exports[`webpack utils dependencies returns default values without any options 1`] = `
Object {
- "exclude": /@babel\\(\\?:\\\\/\\|\\\\\\\\\\{1,2\\}\\)runtime\\|core-js/,
+ "exclude": [Function],
"test": /\\\\\\.\\(js\\|mjs\\)\\$/,
"type": "javascript/auto",
"use": Array [
@@ -40,3 +26,17 @@ Object {
],
}
`;
+
+exports[`webpack utils js returns default values without any options 1`] = `
+Object {
+ "include": [Function],
+ "test": /\\\\\\.\\(js\\|mjs\\|jsx\\)\\$/,
+ "type": "javascript/auto",
+ "use": Array [
+ Object {
+ "loader": "/packages/gatsby/src/utils/babel-loader.js",
+ "options": Object {},
+ },
+ ],
+}
+`;
diff --git a/packages/gatsby/src/utils/__tests__/webpack-utils.js b/packages/gatsby/src/utils/__tests__/webpack-utils.js
index 14951ba0f1969..9fa0fc1d76091 100644
--- a/packages/gatsby/src/utils/__tests__/webpack-utils.js
+++ b/packages/gatsby/src/utils/__tests__/webpack-utils.js
@@ -21,15 +21,126 @@ describe(`webpack utils`, () => {
expect(rule).toMatchSnapshot()
})
+ describe(`include function`, () => {
+ let js
+ beforeAll(() => {
+ js = config.rules.js({
+ modulesThatUseGatsby: [
+ {
+ name: `gatsby-seo`,
+ path: `/Users/sidharthachatterjee/Code/gatsby-seo-test/node_modules/gatsby-seo`,
+ },
+ ],
+ })
+ })
+ it(`includes source files from user code`, () => {
+ expect(
+ js.include(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/src/pages/index.js`
+ )
+ ).toEqual(true)
+ })
+ it(`includes files from .cache`, () => {
+ expect(
+ js.include(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/.cache/production-app.js`
+ )
+ ).toEqual(true)
+ })
+ it(`includes dependencies that use gatsby`, () => {
+ expect(
+ js.include(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/node_modules/gatsby-seo/index.js`
+ )
+ ).toEqual(true)
+ })
+ it(`does not include other dependencies`, () => {
+ expect(
+ js.include(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/node_modules/react/index.js`
+ )
+ ).toEqual(false)
+ })
+ it(`includes gatsby-browser.js`, () => {
+ expect(
+ js.include(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/gatsby-browser.js`
+ )
+ ).toEqual(true)
+ })
+ })
+ })
+ describe(`dependencies`, () => {
it(`adds dependency rule`, () => {
expect(config.rules.dependencies).toEqual(expect.any(Function))
})
-
it(`returns default values without any options`, () => {
const rule = config.rules.dependencies()
expect(rule).toMatchSnapshot()
})
+ describe(`exclude function`, () => {
+ let dependencies
+ beforeAll(() => {
+ dependencies = config.rules.dependencies({
+ modulesThatUseGatsby: [
+ {
+ name: `gatsby-seo`,
+ path: `/Users/sidharthachatterjee/Code/gatsby-seo-test/node_modules/gatsby-seo`,
+ },
+ ],
+ })
+ })
+ it(`excludes source files from user code`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/src/pages/index.js`
+ )
+ ).toEqual(true)
+ })
+ it(`excludes files from .cache`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/.cache/production-app.js`
+ )
+ ).toEqual(true)
+ })
+ it(`excludes dependencies that use gatsby`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/node_modules/gatsby-seo/index.js`
+ )
+ ).toEqual(true)
+ })
+ it(`excludes babel-runtime`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/misiek/test/pr15285/node_modules/@babel/runtime/helpers/interopRequireDefault.js`
+ )
+ ).toEqual(true)
+ })
+ it(`excludes core-js`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/misiek/test/pr15285/node_modules/core-js/modules/es6.array.iterator.js`
+ )
+ ).toEqual(true)
+ })
+ it(`includes dependencies that don't use gatsby`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/node_modules/react/index.js`
+ )
+ ).toEqual(false)
+ })
+ it(`excludes gatsby-browser.js`, () => {
+ expect(
+ dependencies.exclude(
+ `/Users/sidharthachatterjee/Code/gatsby-seo-test/gatsby-browser.js`
+ )
+ ).toEqual(true)
+ })
+ })
})
})
diff --git a/packages/gatsby/src/utils/__tests__/webpack.config.js b/packages/gatsby/src/utils/__tests__/webpack.config.js
index 2789094dde1b1..544a792599b81 100644
--- a/packages/gatsby/src/utils/__tests__/webpack.config.js
+++ b/packages/gatsby/src/utils/__tests__/webpack.config.js
@@ -55,7 +55,7 @@ describe(`basic functionality`, () => {
)
)
)
- })
+ }, 30000)
})
describe(`environment variables`, () => {
diff --git a/packages/gatsby/src/utils/gatsby-dependents.js b/packages/gatsby/src/utils/gatsby-dependents.js
index 6ccb8297686c1..8b1a5822ef3da 100644
--- a/packages/gatsby/src/utils/gatsby-dependents.js
+++ b/packages/gatsby/src/utils/gatsby-dependents.js
@@ -1,10 +1,11 @@
import { store } from "../redux"
+import { memoize } from "lodash"
import rpt from "read-package-tree"
import { promisify } from "util"
const rptAsync = promisify(rpt)
// Returns [Object] with name and path
-module.exports = async () => {
+module.exports = memoize(async () => {
const { program } = store.getState()
const allNodeModules = await rptAsync(
program.directory,
@@ -12,4 +13,4 @@ module.exports = async () => {
(node, moduleName) => /gatsby/.test(moduleName) && moduleName !== `gatsby`
)
return allNodeModules.children
-}
+})
diff --git a/packages/gatsby/src/utils/webpack-utils.js b/packages/gatsby/src/utils/webpack-utils.js
index d47963ecc85be..3f37c6b439980 100644
--- a/packages/gatsby/src/utils/webpack-utils.js
+++ b/packages/gatsby/src/utils/webpack-utils.js
@@ -290,13 +290,27 @@ module.exports = async ({
const rules = {}
/**
- * JavaScript loader via babel, excludes node_modules
+ * JavaScript loader via babel, includes userland code
+ * and packages that depend on `gatsby`
*/
{
- let js = (options = {}) => {
+ let js = (
+ { modulesThatUseGatsby, ...options } = { modulesThatUseGatsby: [] }
+ ) => {
return {
test: /\.(js|mjs|jsx)$/,
- exclude: vendorRegex,
+ include: modulePath => {
+ // when it's not coming from node_modules we treat it as a source file.
+ if (!vendorRegex.test(modulePath)) {
+ return true
+ }
+
+ // If the module uses Gatsby as a dependency
+ // we want to treat it as src so we can extract queries
+ return modulesThatUseGatsby.some(module =>
+ modulePath.includes(module.path)
+ )
+ },
type: `javascript/auto`,
use: [loaders.js(options)],
}
@@ -306,10 +320,14 @@ module.exports = async ({
}
/**
- * Node_modules JavaScript loader via babel (exclude core-js & babel-runtime to speedup babel transpilation)
+ * Node_modules JavaScript loader via babel
+ * Excludes core-js & babel-runtime to speedup babel transpilation
+ * Excludes modules that use Gatsby since the `rules.js` already transpiles those
*/
{
- let dependencies = (options = {}) => {
+ let dependencies = (
+ { modulesThatUseGatsby, ...options } = { modulesThatUseGatsby: [] }
+ ) => {
const jsOptions = {
babelrc: false,
configFile: false,
@@ -326,7 +344,28 @@ module.exports = async ({
return {
test: /\.(js|mjs)$/,
- exclude: /@babel(?:\/|\\{1,2})runtime|core-js/,
+ exclude: modulePath => {
+ if (vendorRegex.test(modulePath)) {
+ // If dep uses Gatsby, exclude
+ if (
+ modulesThatUseGatsby.some(module =>
+ modulePath.includes(module.path)
+ )
+ ) {
+ return true
+ }
+ // If dep is babel-runtime or core-js, exclude
+ if (/@babel(?:\/|\\{1,2})runtime|core-js/.test(modulePath)) {
+ return true
+ }
+
+ // If dep is in node_modules and none of the above, include
+ return false
+ }
+
+ // If dep is user land code, exclude
+ return true
+ },
type: `javascript/auto`,
use: [loaders.js(jsOptions)],
}
diff --git a/packages/gatsby/src/utils/webpack.config.js b/packages/gatsby/src/utils/webpack.config.js
index d38d8801c09cb..8619777042172 100644
--- a/packages/gatsby/src/utils/webpack.config.js
+++ b/packages/gatsby/src/utils/webpack.config.js
@@ -11,6 +11,7 @@ const getPublicPath = require(`./get-public-path`)
const debug = require(`debug`)(`gatsby:webpack-config`)
const report = require(`gatsby-cli/lib/reporter`)
const { withBasePath, withTrailingSlash } = require(`./path`)
+const getGatsbyDependents = require(`./gatsby-dependents`)
const apiRunnerNode = require(`./api-runner-node`)
const createUtils = require(`./webpack-utils`)
@@ -23,6 +24,7 @@ const hasLocalEslint = require(`./local-eslint-config-finder`)
// 4) build-html: build all HTML files
module.exports = async (program, directory, suppliedStage) => {
+ const modulesThatUseGatsby = await getGatsbyDependents()
const directoryPath = withBasePath(directory)
process.env.GATSBY_BUILD_STAGE = suppliedStage
@@ -249,7 +251,9 @@ module.exports = async (program, directory, suppliedStage) => {
// Common config for every env.
// prettier-ignore
let configRules = [
- rules.js(),
+ rules.js({
+ modulesThatUseGatsby,
+ }),
rules.yaml(),
rules.fonts(),
rules.images(),
@@ -260,7 +264,11 @@ module.exports = async (program, directory, suppliedStage) => {
// Speedup 🏎️💨 the build! We only include transpilation of node_modules on javascript production builds
// TODO create gatsby plugin to enable this behaviour on develop (only when people are requesting this feature)
if (stage === `build-javascript`) {
- configRules.push(rules.dependencies())
+ configRules.push(
+ rules.dependencies({
+ modulesThatUseGatsby,
+ })
+ )
}
if (store.getState().themes.themes) {