Skip to content

Commit

Permalink
fix: don't fail entire build when gatsby-config fails to be imported (#…
Browse files Browse the repository at this point in the history
…562)

* add failing test

* fix: don't fail entire build when gatsby-config fails to be imported

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
pieh and kodiakhq[bot] authored Mar 13, 2023
1 parent 5874f67 commit 007c823
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"test": "run-s format install:demo build:demo test:unit test:e2e",
"test:unit": "jest",
"test:e2e": "run-s test:e2e:*",
"test:e2e:v3": "cd plugin/test && ./v3-e2e-test.sh",
"test:e2e:v4": "cd plugin/test && ./v4-e2e-test.sh",
"test:e2e:v5": "cd plugin/test && ./v5-e2e-test.sh",
"format": "run-s format:check-fix:*",
Expand Down
46 changes: 31 additions & 15 deletions plugin/src/helpers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,15 @@ export async function spliceConfig({
return fs.writeFile(fileName, out)
}

function loadGatsbyConfig({ gatsbyRoot, utils }): GatsbyConfig | never {
function loadGatsbyConfig({ gatsbyRoot }): GatsbyConfig {
const gatsbyConfigFile = resolve(gatsbyRoot, 'gatsby-config.js')

if (!existsSync(gatsbyConfigFile)) {
return {}
}

try {
// eslint-disable-next-line n/global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires
return require(gatsbyConfigFile) as GatsbyConfig
} catch (error) {
utils.build.failBuild('Could not load gatsby-config.js', { error })
}
// eslint-disable-next-line n/global-require, import/no-dynamic-require, @typescript-eslint/no-var-requires
return require(gatsbyConfigFile) as GatsbyConfig
}

function hasPlugin(plugins: PluginRef[], pluginName: string): boolean {
Expand All @@ -85,15 +81,12 @@ function hasPlugin(plugins: PluginRef[], pluginName: string): boolean {
)
}

export async function checkConfig({ utils, netlifyConfig }): Promise<void> {
const gatsbyRoot = getGatsbyRoot(netlifyConfig.build.publish)

async function checkGatsbyPluginsCompatibility({
utils,
gatsbyRoot,
gatsbyConfig,
}): Promise<void> | never {
// warn if gatsby-plugin-netlify is missing
const gatsbyConfig = loadGatsbyConfig({
utils,
gatsbyRoot,
})

if (hasPlugin(gatsbyConfig.plugins, 'gatsby-plugin-netlify')) {
if (
!(await checkPackageVersion(
Expand Down Expand Up @@ -121,6 +114,29 @@ export async function checkConfig({ utils, netlifyConfig }): Promise<void> {
)
utils.build.failBuild('Incompatible Gatsby plugin installed')
}
}

export async function checkConfig({ utils, netlifyConfig }): Promise<void> {
const gatsbyRoot = getGatsbyRoot(netlifyConfig.build.publish)

let gatsbyConfig: GatsbyConfig | undefined
try {
gatsbyConfig = loadGatsbyConfig({
gatsbyRoot,
})
} catch (error) {
console.error(
`Could not load gatsby-config.js: ${error.message}\n\nUnable to validate if 'gatsby-plugin-netlify' is setup correctly.`,
)
}

if (gatsbyConfig) {
await checkGatsbyPluginsCompatibility({
utils,
gatsbyConfig,
gatsbyRoot,
})
}

if (
netlifyConfig.plugins.some(
Expand Down
6 changes: 6 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
.cache/
public
.netlify/cache
.netlify/functions
package-lock.json
14 changes: 14 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
The BSD Zero Clause License (0BSD)

Copyright (c) 2020 Gatsby Inc.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
14 changes: 14 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/e2e-tests/build.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// eslint-disable-next-line node/no-unpublished-require
const { buildSite } = require('../../../../helpers')

jest.setTimeout(120_000)
describe('A site with "--require esm" and gatsby-config.js authored in ESM', () => {
it('successfully builds and warns that is unable to validate gatsby-config', async () => {
const { success, logs } = await buildSite()
expect(success).toBeTruthy()
expect(logs.stderr)
.toMatch(`Could not load gatsby-config.js: Cannot use import statement outside a module
Unable to validate if 'gatsby-plugin-netlify' is setup correctly.`)
})
})
3 changes: 3 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ActualConfig from './actual-gatsby-config.js'

module.exports = ActualConfig
6 changes: 6 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/netlify.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[build]
command = "npm run build"
publish = "public/"

[[plugins]]
package = "../../../../src/index.ts"
30 changes: 30 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "esm-gatsby-config",
"version": "1.0.0",
"private": true,
"description": "My Gatsby site",
"author": "Michal Piechowiak",
"keywords": [
"gatsby"
],
"scripts": {
"develop": "cross-env NODE_OPTIONS=\"-r esm\" gatsby develop",
"start": "cross-env NODE_OPTIONS=\"-r esm\" gatsby develop",
"build": "cross-env NODE_OPTIONS=\"-r esm\" gatsby build",
"serve": "cross-env NODE_OPTIONS=\"-r esm\" gatsby serve",
"clean": "gatsby clean",
"jest": "jest",
"test": "npm run build && jest"
},
"license": "0BSD",
"dependencies": {
"cross-env": "^7.0.3",
"esm": "^3.2.25",
"gatsby": "^3.15.0",
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"devDependencies": {
"jest": "^27.0.4"
}
}
52 changes: 52 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/src/pages/404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Link } from 'gatsby'
import * as React from 'react'

// styles
const pageStyles = {
color: '#232129',
padding: '96px',
fontFamily: '-apple-system, Roboto, sans-serif, serif',
}
const headingStyles = {
marginTop: 0,
marginBottom: 64,
maxWidth: 320,
}

const paragraphStyles = {
marginBottom: 48,
}
const codeStyles = {
color: '#8A6534',
padding: 4,
backgroundColor: '#FFF4DB',
fontSize: '1.25rem',
borderRadius: 4,
}

// markup
const NotFoundPage = () => (
<main style={pageStyles}>
<title>Not found</title>
<h1 style={headingStyles}>Page not found</h1>
<p style={paragraphStyles}>
Sorry{' '}
<span role="img" aria-label="Pensive emoji">
😔
</span>{' '}
we couldn’t find what you were looking for.
<br />
{process.env.NODE_ENV === 'development' ? (
<>
<br />
Try creating a page in <code style={codeStyles}>src/pages/</code>.
<br />
</>
) : null}
<br />
<Link to="/">Go home</Link>.
</p>
</main>
)

export default NotFoundPage
182 changes: 182 additions & 0 deletions plugin/test/fixtures/v3/esm-gatsby-config/src/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import * as React from 'react'

// styles
const pageStyles = {
color: '#232129',
padding: 96,
fontFamily: '-apple-system, Roboto, sans-serif, serif',
}
const headingStyles = {
marginTop: 0,
marginBottom: 64,
maxWidth: 320,
}
const headingAccentStyles = {
color: '#663399',
}
const paragraphStyles = {
marginBottom: 48,
}
const codeStyles = {
color: '#8A6534',
padding: 4,
backgroundColor: '#FFF4DB',
fontSize: '1.25rem',
borderRadius: 4,
}
const listStyles = {
marginBottom: 96,
paddingLeft: 0,
}
const listItemStyles = {
fontWeight: 300,
fontSize: 24,
maxWidth: 560,
marginBottom: 30,
}

const linkStyle = {
color: '#8954A8',
fontWeight: 'bold',
fontSize: 16,
verticalAlign: '5%',
}

const docLinkStyle = {
...linkStyle,
listStyleType: 'none',
marginBottom: 24,
}

const descriptionStyle = {
color: '#232129',
fontSize: 14,
marginTop: 10,
marginBottom: 0,
lineHeight: 1.25,
}

const docLink = {
text: 'Documentation',
url: 'https://www.gatsbyjs.com/docs/',
color: '#8954A8',
}

const badgeStyle = {
color: '#fff',
backgroundColor: '#088413',
border: '1px solid #088413',
fontSize: 11,
fontWeight: 'bold',
letterSpacing: 1,
borderRadius: 4,
padding: '4px 6px',
display: 'inline-block',
position: 'relative',
top: -2,
marginLeft: 10,
lineHeight: 1,
}

// data
const links = [
{
text: 'Tutorial',
url: 'https://www.gatsbyjs.com/docs/tutorial/',
description:
"A great place to get started if you're new to web development. Designed to guide you through setting up your first Gatsby site.",
color: '#E95800',
},
{
text: 'How to Guides',
url: 'https://www.gatsbyjs.com/docs/how-to/',
description:
"Practical step-by-step guides to help you achieve a specific goal. Most useful when you're trying to get something done.",
color: '#1099A8',
},
{
text: 'Reference Guides',
url: 'https://www.gatsbyjs.com/docs/reference/',
description:
"Nitty-gritty technical descriptions of how Gatsby works. Most useful when you need detailed information about Gatsby's APIs.",
color: '#BC027F',
},
{
text: 'Conceptual Guides',
url: 'https://www.gatsbyjs.com/docs/conceptual/',
description:
'Big-picture explanations of higher-level Gatsby concepts. Most useful for building understanding of a particular topic.',
color: '#0D96F2',
},
{
text: 'Plugin Library',
url: 'https://www.gatsbyjs.com/plugins',
description:
'Add functionality and customize your Gatsby site or app with thousands of plugins built by our amazing developer community.',
color: '#8EB814',
},
{
text: 'Build and Host',
url: 'https://www.gatsbyjs.com/cloud',
badge: true,
description:
'Now you’re ready to show the world! Give your Gatsby site superpowers: Build and host on Gatsby Cloud. Get started for free!',
color: '#663399',
},
]

// markup
const IndexPage = () => (
<main style={pageStyles}>
<title>Home Page</title>
<h1 style={headingStyles}>
Congratulations
<br />
<span style={headingAccentStyles}>— you just made a Gatsby site! </span>
<span role="img" aria-label="Party popper emojis">
🎉🎉🎉
</span>
</h1>
<p style={paragraphStyles}>
Edit <code style={codeStyles}>src/pages/index.js</code> to see this page
update in real-time.{' '}
<span role="img" aria-label="Sunglasses smiley emoji">
😎
</span>
</p>
<ul style={listStyles}>
<li style={docLinkStyle}>
<a
style={linkStyle}
href={`${docLink.url}?utm_source=starter&utm_medium=start-page&utm_campaign=minimal-starter`}
>
{docLink.text}
</a>
</li>
{links.map((link) => (
<li key={link.url} style={{ ...listItemStyles, color: link.color }}>
<span>
<a
style={linkStyle}
href={`${link.url}?utm_source=starter&utm_medium=start-page&utm_campaign=minimal-starter`}
>
{link.text}
</a>
{link.badge && (
<span style={badgeStyle} aria-label="New Badge">
NEW!
</span>
)}
<p style={descriptionStyle}>{link.description}</p>
</span>
</li>
))}
</ul>
<img
alt="Gatsby G Logo"
src="data:image/svg+xml,%3Csvg width='24' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 2a10 10 0 110 20 10 10 0 010-20zm0 2c-3.73 0-6.86 2.55-7.75 6L14 19.75c3.45-.89 6-4.02 6-7.75h-5.25v1.5h3.45a6.37 6.37 0 01-3.89 4.44L6.06 9.69C7 7.31 9.3 5.63 12 5.63c2.13 0 4 1.04 5.18 2.65l1.23-1.06A7.959 7.959 0 0012 4zm-8 8a8 8 0 008 8c.04 0 .09 0-8-8z' fill='%23639'/%3E%3C/svg%3E"
/>
</main>
)

export default IndexPage
Loading

0 comments on commit 007c823

Please sign in to comment.