Skip to content

Commit

Permalink
feat(gatsby-core-utils,gatsby-cli): Allow write to gatsby-config.ts (#…
Browse files Browse the repository at this point in the history
…35074)

Co-authored-by: Lennart <lekoarts@gmail.com>
  • Loading branch information
tyhopp and LekoArts committed Mar 14, 2022
1 parent fb9c014 commit 56fbf8d
Show file tree
Hide file tree
Showing 13 changed files with 613 additions and 166 deletions.
1 change: 1 addition & 0 deletions packages/gatsby-cli/package.json
Expand Up @@ -14,6 +14,7 @@
"@babel/core": "^7.15.5",
"@babel/generator": "^7.16.8",
"@babel/helper-plugin-utils": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@babel/runtime": "^7.15.4",
"@babel/template": "^7.16.7",
"@babel/types": "^7.16.8",
Expand Down
@@ -0,0 +1,104 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`addPlugins gatsby-config.js should not write with no plugins 1`] = `
"module.exports = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`,
},
plugins: [],
}
"
`;
exports[`addPlugins gatsby-config.js should write a plugin with options 1`] = `
"module.exports = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`
},
plugins: [{
resolve: 'gatsby-plugin-hello',
options: {
\\"greet\\": true
}
}]
};"
`;
exports[`addPlugins gatsby-config.js should write a single plugin 1`] = `
"module.exports = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`
},
plugins: [\\"gatsby-plugin-hello\\"]
};"
`;
exports[`addPlugins gatsby-config.js should write multiple plugins 1`] = `
"module.exports = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`
},
plugins: [\\"gatsby-plugin-hello\\", \\"gatsby-plugin-world\\"]
};"
`;
exports[`addPlugins gatsby-config.ts should not write with no plugins 1`] = `
"import type { GatsbyConfig } from \\"gatsby\\"
const config: GatsbyConfig = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`,
},
plugins: [],
}
export default config
"
`;
exports[`addPlugins gatsby-config.ts should write a plugin with options 1`] = `
"import type { GatsbyConfig } from \\"gatsby\\";
const config: GatsbyConfig = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`
},
plugins: [{
resolve: 'gatsby-plugin-hello',
options: {
\\"greet\\": true
}
}]
};
export default config;
"
`;
exports[`addPlugins gatsby-config.ts should write a single plugin 1`] = `
"import type { GatsbyConfig } from \\"gatsby\\";
const config: GatsbyConfig = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`
},
plugins: [\\"gatsby-plugin-hello\\"]
};
export default config;
"
`;
exports[`addPlugins gatsby-config.ts should write multiple plugins 1`] = `
"import type { GatsbyConfig } from \\"gatsby\\";
const config: GatsbyConfig = {
siteMetadata: {
siteUrl: \`https://www.yourdomain.tld\`
},
plugins: [\\"gatsby-plugin-hello\\", \\"gatsby-plugin-world\\"]
};
export default config;
"
`;
120 changes: 120 additions & 0 deletions packages/gatsby-cli/src/__tests__/handlers/plugin-add.ts
@@ -0,0 +1,120 @@
import { ensureDir, copyFile, readFile, rm } from "fs-extra"
import { join } from "path"
import { addPlugins } from "../../handlers/plugin-add"

/**
* Copy files from minimal starters instead of testing against static gatsby-configs
* in fixtues so that these break if we change the starter configs in a breaking way.
*
* Not using `jest.each` since I find that much harder to read and debug.
* @see {@link https://jestjs.io/docs/api#testeachtablename-fn-timeout}
*/

const root = join(__dirname, `../../../../..`)
const fixtures = join(__dirname, `../fixtures`)
const config = {
js: {
starter: `${root}/starters/gatsby-starter-minimal/gatsby-config.js`,
fixture: `${fixtures}/gatsby-config.js`,
},
ts: {
starter: `${root}/starters/gatsby-starter-minimal-ts/gatsby-config.ts`,
fixture: `${fixtures}/gatsby-config.ts`,
},
}
const plugin = {
hello: `gatsby-plugin-hello`,
world: `gatsby-plugin-world`,
}

describe(`addPlugins`, () => {
beforeAll(async () => {
await ensureDir(fixtures)
})

describe(`gatsby-config.js`, () => {
beforeEach(async () => {
await copyFile(config.js.starter, config.js.fixture)
})

afterEach(async () => {
await rm(config.js.fixture)
})

it(`should not write with no plugins`, async () => {
await addPlugins([], {}, fixtures, [])
const gatsbyConfig = (await readFile(config.js.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})

it(`should write a single plugin`, async () => {
await addPlugins([plugin.hello], {}, fixtures, [])
const gatsbyConfig = (await readFile(config.js.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})

it(`should write multiple plugins`, async () => {
await addPlugins([plugin.hello, plugin.world], {}, fixtures, [])
const gatsbyConfig = (await readFile(config.js.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})

it(`should write a plugin with options`, async () => {
await addPlugins(
[plugin.hello],
{
[plugin.hello]: {
greet: true,
},
},
fixtures,
[]
)
const gatsbyConfig = (await readFile(config.js.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})
})

describe.skip(`gatsby-config.ts`, () => {
beforeEach(async () => {
await copyFile(config.ts.starter, config.ts.fixture)
})

afterEach(async () => {
await rm(config.ts.fixture)
})

it(`should not write with no plugins`, async () => {
await addPlugins([], {}, fixtures, [])
const gatsbyConfig = (await readFile(config.ts.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})

it(`should write a single plugin`, async () => {
await addPlugins([plugin.hello], {}, fixtures, [])
const gatsbyConfig = (await readFile(config.ts.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})

it(`should write multiple plugins`, async () => {
await addPlugins([plugin.hello, plugin.world], {}, fixtures, [])
const gatsbyConfig = (await readFile(config.ts.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})

it(`should write a plugin with options`, async () => {
await addPlugins(
[plugin.hello],
{
[plugin.hello]: {
greet: true,
},
},
fixtures,
[]
)
const gatsbyConfig = (await readFile(config.ts.fixture)).toString()
expect(gatsbyConfig).toMatchSnapshot()
})
})
})
60 changes: 43 additions & 17 deletions packages/gatsby-cli/src/handlers/plugin-add-utils.ts
Expand Up @@ -7,11 +7,12 @@ import {
getConfigPath,
getConfigStore,
} from "gatsby-core-utils"
import { transform } from "@babel/core"
import { BabelPluginAddPluginsToGatsbyConfig } from "./plugin-babel-utils"
import { transform, TransformOptions } from "@babel/core"
import BabelPluginAddPluginsToGatsbyConfig from "./plugin-babel-utils"

const addPluginToConfig = (
src: string,
srcPath: string,
{
name,
options,
Expand All @@ -22,19 +23,41 @@ const addPluginToConfig = (
key: string
}
): string => {
const addPlugins = new BabelPluginAddPluginsToGatsbyConfig({
pluginOrThemeName: name,
options,
shouldAdd: true,
key,
})
let code

// @ts-ignore - fix me
const { code } = transform(src, {
// @ts-ignore - fix me
plugins: [addPlugins.plugin],
configFile: false,
})
try {
const transformOptions: TransformOptions = {
plugins: [
[
BabelPluginAddPluginsToGatsbyConfig,
{
pluginOrThemeName: name,
options,
key,
},
],
],
filename: srcPath,
configFile: false,
}

// Use the Babel TS preset if we're operating on `gatsby-config.ts`
if (srcPath.endsWith(`ts`)) {
transformOptions.presets = [`@babel/preset-typescript`]
}

code = transform(src, transformOptions)?.code

// Add back stripped type import, do light formatting, remove added empty module export.
// Use semicolon since Babel does that anyway, and we might as well be consistent.
if (srcPath.endsWith(`ts`)) {
code = `import type { GatsbyConfig } from "gatsby";\n\n${code}`
code = code.replace(`export {};`, ``)
code = code.replace(`export default config;`, `\nexport default config;`)
}
} catch (error) {
console.error(`Failed to transform gatsby config`, error)
}

return code
}
Expand All @@ -53,10 +76,13 @@ export const GatsbyPluginCreate = async ({
key,
}: IGatsbyPluginCreateInput): Promise<void> => {
const release = await lock(`gatsby-config.js`)
const configSrcPath = getConfigPath(root)
const configSrc = await readConfigFile(root)

const code = addPluginToConfig(configSrc, { name, options, key })

const code = addPluginToConfig(configSrc, configSrcPath, {
name,
options,
key,
})
await fs.writeFile(getConfigPath(root), code)
release()
}
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby-cli/src/handlers/plugin-add.ts
Expand Up @@ -54,7 +54,7 @@ async function installPluginConfig(
options,
key: pluginKey,
})
reporter.info(`Installed ${pluginName || pluginKey} in gatsby-config.js`)
reporter.info(`Installed ${pluginName || pluginKey} in gatsby-config`)
} catch (err) {
reporter.error(JSON.parse(err)?.message)
installTimer.setStatus(`FAILED`)
Expand Down

0 comments on commit 56fbf8d

Please sign in to comment.