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

feat(gatsby): Handle duplicated fragment definitions #15179

Merged
merged 14 commits into from
Jul 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 35 additions & 4 deletions packages/gatsby/src/query/query-compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const {
ScalarLeafsRule,
VariablesAreInputTypesRule,
VariablesInAllowedPositionRule,
Kind,
print,
} = require(`graphql`)

type RootQuery = {
Expand Down Expand Up @@ -99,6 +101,7 @@ class Runner {

async parseEverything() {
const filesRegex = path.join(`/**`, `*.+(t|j)s?(x)`)

let files = [
path.join(this.base, `src`),
path.join(this.base, `.cache`, `fragments`),
Expand All @@ -113,18 +116,26 @@ class Runner {
),
[]
)

files = files.filter(d => !d.match(/\.d\.ts$/))

files = files.map(normalize)

// We should be able to remove the following and preliminary tests do suggest
// that they aren't needed anymore since we transpile node_modules now
// However, there could be some cases (where a page is outside of src for example)
// that warrant keeping this and removing later once we have more confidence (and tests)

// Ensure all page components added as they're not necessarily in the
// pages directory e.g. a plugin could add a page component. Plugins
// pages directory e.g. a plugin could add a page component. Plugins
// *should* copy their components (if they add a query) to .cache so that
// our babel plugin to remove the query on building is active (we don't
// run babel on code in node_modules). Otherwise the component will throw
// an error in the browser of "graphql is not defined".
// our babel plugin to remove the query on building is active.
// Otherwise the component will throw an error in the browser of
// "graphql is not defined".
files = files.concat(
Array.from(store.getState().components.keys(), c => normalize(c))
)

files = _.uniq(files)

let parser = new FileParser()
Expand All @@ -138,6 +149,7 @@ class Runner {
const nameDefMap = new Map()
const nameErrorMap = new Map()
const documents = []
const fragmentMap = new Map()

for (let [filePath, doc] of nodes.entries()) {
let errors = validate(this.schema, doc, validationRules)
Expand Down Expand Up @@ -172,6 +184,25 @@ class Runner {
return compiledNodes
}

// The way we currently export fragments requires duplicated ones
// to be filtered out since there is a global Fragment namespace
// We maintain a top level fragment Map to keep track of all definitions
// of thge fragment type and to filter them out if theythey've already been
// declared before
doc.definitions = doc.definitions.filter(definition => {
if (definition.kind === Kind.FRAGMENT_DEFINITION) {
const fragmentName = definition.name.value
if (fragmentMap.has(fragmentName)) {
if (print(definition) === fragmentMap.get(fragmentName)) {
return false
}
} else {
fragmentMap.set(fragmentName, print(definition))
}
}
return true
})

documents.push(doc)
doc.definitions.forEach((def: any) => {
const name: string = def.name.value
Expand Down
4 changes: 1 addition & 3 deletions packages/gatsby/src/utils/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,10 @@ module.exports = async (program, directory, suppliedStage) => {
}

function getModule() {
const jsOptions = {}

// Common config for every env.
// prettier-ignore
let configRules = [
rules.js(jsOptions),
rules.js(),
rules.yaml(),
rules.fonts(),
rules.images(),
Expand Down