Skip to content

Commit

Permalink
Use babel-traverse instead of plugin so graphql queries async
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleAMathews committed Oct 26, 2016
1 parent 3ced3e9 commit a19677e
Showing 1 changed file with 62 additions and 68 deletions.
130 changes: 62 additions & 68 deletions lib/utils/query-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const babylon = require(`babylon`)
import fs from 'fs'
import _ from 'lodash'
const babel = require(`babel-core`)
import traverse from 'babel-traverse'
import path from 'path'
import { graphql } from 'graphql'
import parseFilepath from 'parse-filepath'
Expand Down Expand Up @@ -203,65 +204,6 @@ const babelPlugin = function ({ types: t }) {
const query = chunks.join(``)
console.time(`graphql query time`)
const graphql = state.opts.graphql
_.each(state.opts.paths, (pathInfo) => {
// TODO
// - routeProvider thing + auto routes if component
// isn't a multiple route thingy.
// - Track which json file associated with which wrapper-component
// and delete old one when query changes.
// - Track ids of nodes associated with which queries
// and rerun query for a specific wrapper json file
// when an underying file changes.
// - Also track connections/ranges and mark their components
// as stale (just mark any query against connections stale if a file
// in that connection gets changed, so all ids in that connection.)
// - write plugin which just exports the src component
// instead of the fake HOC
// - Move all this into Gatsby (as seperate package within new Lerna
// structure).
// - schema for paths/pages and other internal info. Generate searchable sitemap page in dev.
// - Markdown schema
// * frontmatter — just skip deciding schema — config takes JOI schema
// for frontmatter though.
// * markdownAST
// * diff ways of parsing Markdown AST e.g. headings
// * bodyRaw
// * bodyHTML
// * timeToRead, etc. (computed/derived fields)
// * path — programatically alterable like now.
// * file info e.g. parseFilepath result.
graphql(query, pathInfo)
.catch(error => console.log(`graphql error`, error))
.then(result => {
if (result.errors) {
console.log(`graphql errors`, result.errors)
}
// Combine the result with the pathInfo.
result.pathContext = pathInfo
// TODO see if can hash actual result not result + context
// which would combine some modules. Probably need to just
// insert the page context in child-routes.
// Also make page context more explicit? E.g. should never
// send component name to browser like we are now.
const resultHash = hashStr(JSON.stringify(result))

// Add result to page object.
const page = pagesDB().get(pathInfo.path)
page.data = result
page.resultHash = resultHash
pagesDB(pagesDB().set(page.path, page))

// Save result to file.
const resultJSON = JSON.stringify(result, null, 4)
let fileName = `${_.kebabCase(pathInfo.path)}.js`
if (fileName === `.js`) {
fileName = `index.js`
}
fs.writeFile(`${state.opts.directory}/.intermediate-representation/json/${resultHash}.json`, resultJSON)
})
})
console.log(`rewrote JSON for queries for ${state.opts.componentPath}`)
console.timeEnd(`graphql query time`)

//path.parentPath.replaceWithSourceString(`require('fixme.json')`);
}
Expand Down Expand Up @@ -289,6 +231,31 @@ const q = queue(({ file, graphql, directory }, callback) => {
console.log(`Failed to parse ${file}`)
console.log(e)
}

// Get query for this file.
let query
traverse(ast, {
TemplateLiteral (path, state) {
if (path.parentPath.parentPath.parentPath.type !== `ExportNamedDeclaration`) {
return
}
const exportPath = path.parentPath.parentPath.parentPath
const name = _.get(exportPath, `node.declaration.declarations[0].id.name`)
if (name === `pageQuery`) {
const quasis = _.get(path, `node.quasis`, [])
const expressions = path.get(`expressions`)
const chunks = []
quasis.forEach((quasi) => {
chunks.push(quasi.value.cooked)
const expr = expressions.shift()
if (expr) {
chunks.push(expr.scope.bindings[expr.node.name].path.get(`value`).parentPath.node.init.quasis[0].value.cooked)
}
})
query = chunks.join(``)
}
},
})
const absFile = path.resolve(file)
// Get paths for this file.
const paths = []
Expand All @@ -305,16 +272,43 @@ const q = queue(({ file, graphql, directory }, callback) => {
}

// Run queries for each page component.
try {
babel.transformFromAst(ast, ``, {
plugins: [[babelPlugin, { ...pathsInfo }]],
console.time(`graphql query time`)
Promise.all(paths.map((pathInfo) => {
return graphql(query, pathInfo)
.catch(error => console.log(`graphql error`, error))
.then(result => {
if (result.errors) {
console.log(`graphql errors`, result.errors)
}
// Combine the result with the pathInfo.
const clonedResult = { ...result }
result.pathContext = pathInfo
const resultHash = hashStr(JSON.stringify(clonedResult))

// Add result to page object.
const page = pagesDB().get(pathInfo.path)
page.resultHash = resultHash
pagesDB(pagesDB().set(page.path, page))

// Save result to file.
const resultJSON = JSON.stringify(clonedResult, null, 4)
let fileName = `${_.kebabCase(pathInfo.path)}.js`
if (fileName === `.js`) {
fileName = `index.js`
}
fs.writeFileSync(`${directory}/.intermediate-representation/json/${resultHash}.json`, resultJSON)

return null
})
} catch (e) {
console.log(`Failed to run queries for ${file}`)
console.log(e)
}
debouncedWriteChildRoutes()
callback()
}))
.then(() => {
console.log(`rewrote JSON for queries for ${absFile}`)
console.timeEnd(`graphql query time`)
// Write out new child-routes.js in the .intermediate-representation directory
// in the root of your site.
debouncedWriteChildRoutes()
callback()
})
}, 2)

module.exports = (program, graphql, cb) => {
Expand Down

0 comments on commit a19677e

Please sign in to comment.