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

recipes: Improve providers #22764

Merged
merged 8 commits into from
Apr 2, 2020
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
31 changes: 19 additions & 12 deletions packages/gatsby/src/recipes/providers/fs/file.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,42 @@
const fs = require(`fs`)
const fs = require(`fs-extra`)
const path = require(`path`)
const { promisify } = require(`util`)
const mkdirp = require(`mkdirp`)

const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const destroyFile = promisify(fs.unlink)
const fileExists = ({ root }, { path: filePath }) => {
const fullPath = path.join(root, filePath)
try {
fs.accessSync(fullPath, fs.constants.F_OK)
return true
} catch (e) {
return false
}
}

const create = async ({ root }, { path: filePath, content, children }) => {
const create = async ({ root }, { path: filePath, content }) => {
const fullPath = path.join(root, filePath)
const { dir } = path.parse(fullPath)

content = content || children

await mkdirp(dir)
await writeFile(fullPath, content)
await fs.writeFile(fullPath, content)
}

const update = create

const read = async ({ root }, { path: filePath }) => {
const fullPath = path.join(root, filePath)
const content = await readFile(fullPath, `utf8`)
const content = await fs.readFile(fullPath, `utf8`)

return { content }
}

const destroy = async ({ root }, { path: filePath }) => {
const fullPath = path.join(root, filePath)
await destroyFile(fullPath)
await fs.unlink(fullPath)
}

module.exports.exists = fileExists

module.exports.create = create
module.exports.update = create
module.exports.update = update
module.exports.read = read
module.exports.destroy = destroy
30 changes: 30 additions & 0 deletions packages/gatsby/src/recipes/providers/fs/file.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const file = require(`./file`)

const root = __dirname
const content = `Hello, world!`

test(`create writes a file`, async () => {
const filePath = `bar.txt`

await file.create({ root }, { path: filePath, content })

const result = await file.read({ root }, { path: filePath })

expect(result.content).toEqual(content)

await file.destroy({ root }, { path: filePath })
})

test(`update overwrites a file`, async () => {
const filePath = `bar.txt`
const newContent = `new content!`

await file.create({ root }, { path: filePath, content })
await file.update({ root }, { path: filePath, content: newContent })

const result = await file.read({ root }, { path: filePath })

expect(result.content).toEqual(newContent)

await file.destroy({ root }, { path: filePath })
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const redish = `#c5484d`

module.exports = {
siteMetadata: {
title: `Bricolage`,
Expand Down Expand Up @@ -63,8 +62,7 @@ module.exports = {
display: `minimal-ui`,
},
},
`gatsby-plugin-offline`,
// `gatsby-plugin-preact`,
`gatsby-plugin-offline`, // `gatsby-plugin-preact`,
`gatsby-plugin-react-helmet`,
],
}
74 changes: 51 additions & 23 deletions packages/gatsby/src/recipes/providers/gatsby/plugin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const fs = require(`fs`)
const fs = require(`fs-extra`)
const path = require(`path`)
const babel = require(`@babel/core`)

Expand All @@ -18,6 +18,31 @@ const isDefaultExport = node => {
return true
}

const getValueFromLiteral = node => {
if (node.type === `StringLiteral`) {
return node.value
}

if (node.type === `TemplateLiteral`) {
return node.quasis[0].value.raw
}

return null
}

const getNameForPlugin = node => {
if (node.type === `StringLiteral` || node.type === `TemplateLiteral`) {
return getValueFromLiteral(node)
}

if (node.type === `ObjectExpression`) {
const resolve = node.properties.find(p => p.key.name === `resolve`)
return resolve ? getValueFromLiteral(resolve.value) : null
}

return null
}

const addPluginToConfig = (src, pluginName) => {
const addPlugins = new BabelPluginAddPluginsToGatsbyConfig({
pluginOrThemeName: pluginName,
Expand All @@ -31,31 +56,35 @@ const addPluginToConfig = (src, pluginName) => {
return code
}

const create = ({ root }, { name }) => {
const configPath = path.join(root, `gatsby-config.js`)
const configSrc = fs.readFileSync(configPath)
const getPluginsFromConfig = src => {
const getPlugins = new BabelPluginGetPluginsFromGatsbyConfig()

const code = addPluginToConfig(configSrc, name)
babel.transform(src, {
plugins: [getPlugins.plugin],
})

fs.writeFileSync(configPath, code)
return getPlugins.state
}

const read = ({ root }) => {
const create = async ({ root }, { name }) => {
const configPath = path.join(root, `gatsby-config.js`)
const configSrc = fs.readFileSync(configPath)
const configSrc = await fs.readFile(configPath, `utf8`)

const getPlugins = new BabelPluginGetPluginsFromGatsbyConfig()
const code = addPluginToConfig(configSrc, name)

babel.transform(configSrc, {
plugins: [getPlugins.plugin],
})
await fs.writeFile(configPath, code)
}

return getPlugins.state
const read = async ({ root }) => {
const configPath = path.join(root, `gatsby-config.js`)
const configSrc = await fs.readFile(configPath, `utf8`)

return getPluginsFromConfig(configSrc)
}

const destroy = ({ root }, { name }) => {
const destroy = async ({ root }, { name }) => {
const configPath = path.join(root, `gatsby-config.js`)
const configSrc = fs.readFileSync(configPath)
const configSrc = await fs.readFile(configPath, `utf8`)

const addPlugins = new BabelPluginAddPluginsToGatsbyConfig({
pluginOrThemeName: name,
Expand All @@ -66,7 +95,7 @@ const destroy = ({ root }, { name }) => {
plugins: [addPlugins.plugin],
})

fs.writeFileSync(configPath, code)
await fs.writeFile(configPath, code)
}

class BabelPluginAddPluginsToGatsbyConfig {
Expand All @@ -88,15 +117,14 @@ class BabelPluginAddPluginsToGatsbyConfig {
const plugins = right.properties.find(p => p.key.name === `plugins`)

if (shouldAdd) {
const exists = plugins.value.elements.some(
node => node.value === pluginOrThemeName
)
const pluginNames = plugins.value.elements.map(getNameForPlugin)
const exists = pluginNames.includes(node.value)
if (!exists) {
plugins.value.elements.push(t.stringLiteral(pluginOrThemeName))
}
} else {
plugins.value.elements = plugins.value.elements.filter(
node => node.value !== pluginOrThemeName
node => getNameForPlugin(node) !== pluginOrThemeName
)
}

Expand Down Expand Up @@ -127,9 +155,8 @@ class BabelPluginGetPluginsFromGatsbyConfig {

const plugins = right.properties.find(p => p.key.name === `plugins`)

plugins.value.elements.forEach(node => {
// TODO: handle { resolve: 'thing' }
this.state.push(node.value)
plugins.value.elements.map(node => {
this.state.push(getNameForPlugin(node))
})
},
},
Expand All @@ -139,6 +166,7 @@ class BabelPluginGetPluginsFromGatsbyConfig {
}

module.exports.addPluginToConfig = addPluginToConfig
module.exports.getPluginsFromConfig = getPluginsFromConfig

module.exports.create = create
module.exports.update = create
Expand Down
35 changes: 28 additions & 7 deletions packages/gatsby/src/recipes/providers/gatsby/plugin.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
const fs = require(`fs`)
const path = require(`path`)

const { addPluginToConfig } = require(`./plugin`)
const plugin = require(`./plugin`)

const CONFIG_PATH = path.join(__dirname, `./fixtures/gatsby-config.js`)
const root = path.join(__dirname, `./fixtures`)
const name = `gatsby-plugin-foo`

test(`babel plugin to get list of plugins and their options!`, () => {
const src = fs.readFileSync(CONFIG_PATH, `utf8`)
describe(`gatsby-config`, () => {
test(`adds a plugin to a gatsby config`, async () => {
await plugin.create({ root }, { name })

const result = addPluginToConfig(src, `gatsby-plugin-foo`)
const result = await plugin.read({ root })

expect(result).toMatch(`gatsby-plugin-foo`)
expect(result).toContain(`gatsby-plugin-foo`)

await plugin.destroy({ root }, { name })
})

test(`retrieves plugins from a config`, async () => {
const result = await plugin.read({ root })

expect(result).toEqual([
`gatsby-source-filesystem`,
`gatsby-transformer-sharp`,
`gatsby-plugin-emotion`,
`gatsby-plugin-typography`,
`gatsby-transformer-remark`,
`gatsby-plugin-sharp`,
`gatsby-plugin-google-analytics`,
`gatsby-plugin-manifest`,
`gatsby-plugin-offline`,
`gatsby-plugin-react-helmet`,
])
})
})
17 changes: 6 additions & 11 deletions packages/gatsby/src/recipes/providers/gatsby/shadow-file.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
const path = require(`path`)
const fs = require(`fs`)
const { promisify } = require(`util`)
const fs = require(`fs-extra`)
const mkdirp = require(`mkdirp`)

const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const destroyFile = promisify(fs.unlink)

const create = async ({ root }, { theme, path: filePath }) => {
const relativePathInTheme = filePath.replace(theme + `/`, ``)
const fullFilePathToShadow = path.join(
Expand All @@ -16,13 +11,13 @@ const create = async ({ root }, { theme, path: filePath }) => {
relativePathInTheme
)

const contents = await readFile(fullFilePathToShadow, `utf8`)
const contents = await fs.readFile(fullFilePathToShadow, `utf8`)

const fullPath = path.join(root, filePath)
const { dir } = path.parse(fullPath)

await mkdirp(dir)
await writeFile(fullPath, contents)
await fs.writeFile(fullPath, contents)
}

const read = async ({ root }, { theme, path: filePath }) => {
Expand All @@ -34,13 +29,13 @@ const read = async ({ root }, { theme, path: filePath }) => {
relativePathInTheme
)

const contents = await readFile(fullFilePathToShadow, `utf8`)
const contents = await fs.readFile(fullFilePathToShadow, `utf8`)
return contents
}

const destroy = async ({ root }, { theme, path: filePath }) => {
const destroy = async ({ root }, { path: filePath }) => {
const fullPath = path.join(root, filePath)
await destroyFile(fullPath)
await fs.unlink(fullPath)
}

module.exports.create = create
Expand Down
5 changes: 4 additions & 1 deletion packages/gatsby/src/recipes/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
- [ ] Step by step design
- [ ] Select input supported recipes
- [ ] Make port selection dynamic
- [x] Use `fs-extra`
- [x] Handle object style plugins
- [x] Improve gatsby-config test
- [ ] use yarn/npm based on the user config

## Near-ish future

- [ ] Make a proper "Config" provider to add recipes dir, store data, etc.
- [ ] Client sends the MDX file to the server (maybe?)
- [ ] Move parsing to the server