diff --git a/lib/bin/cli.js b/lib/bin/cli.js index 17649c4f6e479..edf6289c82d53 100644 --- a/lib/bin/cli.js +++ b/lib/bin/cli.js @@ -4,76 +4,107 @@ const fs = require('fs-extra') const path = require('path') import _ from 'lodash' -// Copy our load-context function to root of site in a dot file. -const gatsbyFile = `${__dirname}/../utils/load-context.js` -const siteDirectory = path.resolve('.') -const fileName = `${siteDirectory}/.gatsby-context.js` -fs.copy(gatsbyFile, fileName) - const defaultHost = process.platform === 'win32' ? 'localhost' : '0.0.0.0' const directory = path.resolve('.') +const HOST_OPTION_ARGS = [ + '-H, --host ', + `Hostname at which to start the server. Defaults to ${defaultHost}.`, + defaultHost, +] +const PAGES_PATH_OPTION_ARGS = [ + '-P, --pagesPath ', + 'Path to a collection of page source files. ' + + 'Defaults to `./pages`.', + './pages', +] +const PORT_OPTION_ARGS = [ + '-p, --port ', + 'Port to start the server on. Defaults to 8000.', + 8000, +] +const OPEN_OPTION_ARGS = [ + '-o, --open', + 'Open a browser window once the server has started.', + false, +] + +function writeGatsbyContextFile (pagesPath) { + // Copy our load-context function to root of site in a dot file. + const getLoadContext = require( + path.resolve(__dirname, '..', 'utils', 'get-load-context.js'), + ) + fs.writeFile( + path.resolve('.', '.gatsby-context.js'), + getLoadContext(path.relative(directory, pagesPath)), + ) +} + +function prepareOptions (command) { + const options = { + ...command, + directory, + } + if (command.pagesPath) { + options.pagesPath = path.resolve(directory, command.pagesPath) + } + return options +} + +function getCommandHandler (fn) { + return function (command) { + const options = prepareOptions(command) + writeGatsbyContextFile(options.pagesPath) + fn(options) + } +} + program .version(packageJson.version) .usage('[command] [options]') program.command('develop') .description('Start development server. Watches files and rebuilds and hot reloads if something changes') // eslint-disable-line max-len - .option('-H, --host ', - `Set host. Defaults to ${defaultHost}`, - defaultHost - ) - .option('-p, --port ', 'Set port. Defaults to 8000', '8000') - .option('-o, --open', 'Open the site in your browser for you.') - .action((command) => { + .option(...HOST_OPTION_ARGS) + .option(...OPEN_OPTION_ARGS) + .option(...PORT_OPTION_ARGS) + .option(...PAGES_PATH_OPTION_ARGS) + .action(getCommandHandler(options => { const develop = require('../utils/develop') - const p = { - ...command, - directory, - } - develop(p) - }) + develop(options) + })) program.command('build') .description('Build a Gatsby project.') + .option(...PAGES_PATH_OPTION_ARGS) .option('--prefix-links', 'Build site with links prefixed (set prefix in your config).') - .action((command) => { + .action(getCommandHandler(options => { // Set NODE_ENV to 'production' process.env.NODE_ENV = 'production' const build = require('../utils/build') - const p = { - ...command, - directory, - } - build(p, (err) => { + build(options, (err) => { if (err) { throw err } else { console.log('Done') } }) - }) + })) program.command('serve-build') .description('Serve built site.') - .option('-H, --host ', - `Set host. Defaults to ${defaultHost}`, - defaultHost - ) - .option('-p, --port ', 'Set port. Defaults to 8000', '8000') - .option('-o, --open', 'Open the site in your browser for you.') - .action((command) => { + .option(...HOST_OPTION_ARGS) + .option(...OPEN_OPTION_ARGS) + .option(...PAGES_PATH_OPTION_ARGS) + .option(...PORT_OPTION_ARGS) + .action(getCommandHandler(options => { const serve = require('../utils/serve-build') - const p = { - ...command, - directory, - } - serve(p) - }) + serve(options) + })) program .command('new [rootPath] [starter]') diff --git a/lib/isomorphic/create-routes.js b/lib/isomorphic/create-routes.js index 0db9256d6436a..309324c06ea80 100644 --- a/lib/isomorphic/create-routes.js +++ b/lib/isomorphic/create-routes.js @@ -10,9 +10,10 @@ module.exports = (files, pagesReq) => { file.file.name === '_template' ) + const rootTemplate = templates.find(t => t.templatePath === '/') const routes = { path: prefixLink('/'), - component: require('pages/_template'), + component: rootTemplate ? pagesReq(`./${rootTemplate.requirePath}`) : null, childRoutes: [], indexRoute: {}, pages, diff --git a/lib/loaders/config-loader/index.js b/lib/loaders/config-loader/index.js index 6c4ce7ce28b9b..f2f2c253a8ac1 100644 --- a/lib/loaders/config-loader/index.js +++ b/lib/loaders/config-loader/index.js @@ -7,13 +7,14 @@ const globPages = require('../../utils/glob-pages') module.exports = function (source) { this.cacheable() const callback = this.async() - const directory = loaderUtils.parseQuery(this.query).directory + const pagesPath = loaderUtils.parseQuery(this.query).pagesPath const config = toml.parse(source) const value = {} value.config = config - value.relativePath = path.relative('.', directory) - globPages(directory, (err, pagesData) => { + value.relativePath = path.relative('.', pagesPath) + + globPages(pagesPath, (err, pagesData) => { value.pages = pagesData return callback(null, `module.exports = ${JSON.stringify(value, void 0, '\t')}`) }) diff --git a/lib/utils/build-html.js b/lib/utils/build-html.js index b6b56b718d8fa..732ea446e39cb 100644 --- a/lib/utils/build-html.js +++ b/lib/utils/build-html.js @@ -7,9 +7,12 @@ import fs from 'fs' const debug = require('debug')('gatsby:html') module.exports = (program, callback) => { - const { directory } = program + const { + directory, + pagesPath, + } = program - globPages(directory, (err, pages) => { + globPages(pagesPath, (err, pages) => { debug('generating static HTML') const routes = pages.filter((page) => page.path).map((page) => page.path) diff --git a/lib/utils/build-page/index.js b/lib/utils/build-page/index.js index 039371ea82466..c57866ec23267 100644 --- a/lib/utils/build-page/index.js +++ b/lib/utils/build-page/index.js @@ -4,10 +4,9 @@ import objectAssign from 'object-assign' import pathResolver from './path-resolver' import loadFrontmatter from './load-frontmatter' -export default function buildPage (directory: string, page: string) { +export default function buildPage (pagesPath: string, page: string) { const pageData = loadFrontmatter(page) - - const relativePath: string = path.relative(path.join(directory, 'pages'), page) + const relativePath: string = path.relative(pagesPath, page) const pathData = pathResolver(relativePath, pageData) return objectAssign({}, pathData, { data: pageData }) diff --git a/lib/utils/build-page/path-resolver.js b/lib/utils/build-page/path-resolver.js index b84acc3c6f5c3..a8f62b30ed052 100644 --- a/lib/utils/build-page/path-resolver.js +++ b/lib/utils/build-page/path-resolver.js @@ -1,9 +1,9 @@ /* @flow */ -import slash from 'slash' import parsePath from 'parse-filepath' +import path from 'path' +import slash from 'slash' import urlResolver from './url-resolver' - export default function pathResolver (relativePath: string, pageData: {} = {}) { const data = {} @@ -23,9 +23,8 @@ export default function pathResolver (relativePath: string, pageData: {} = {}) { // Set the "template path" if (data.file.name === '_template') { - data.templatePath = `/${data.file.dirname}/` + data.templatePath = path.join(path.sep, data.file.dirname, path.sep) } return data } - diff --git a/lib/utils/build.js b/lib/utils/build.js index 1d1939bfcffc3..f5ca81acb3e37 100644 --- a/lib/utils/build.js +++ b/lib/utils/build.js @@ -25,7 +25,7 @@ function customPost (program, callback) { if (customPostBuild) { console.log('Performing custom post-build steps') - return globPages(directory, (globError, pages) => + return globPages(program.pagesPath, (globError, pages) => customPostBuild(pages, (error) => { if (error) { console.log('customPostBuild function failed') diff --git a/lib/utils/develop.js b/lib/utils/develop.js index 103f34c6a9f1e..12ba99e4a0338 100644 --- a/lib/utils/develop.js +++ b/lib/utils/develop.js @@ -30,7 +30,7 @@ function startServer (program, launchPort) { const serverPort = launchPort || program.port // Load pages for the site. - return globPages(directory, (err, pages) => { + return globPages(program.pagesPath, (err, pages) => { const compilerConfig = webpackConfig(program, directory, 'develop', program.port) const compiler = webpack(compilerConfig.resolve()) @@ -90,7 +90,7 @@ function startServer (program, launchPort) { path: '/{path*}', handler: { directory: { - path: `${program.directory}/pages`, + path: program.pagesPath, listing: false, index: false, }, @@ -104,7 +104,7 @@ function startServer (program, launchPort) { const parsed = parsePath(request.path) const page = _.find(pages, (p) => p.path === (`${parsed.dirname}/`)) - let absolutePath = `${program.directory}/pages` + let absolutePath = program.pagesPath let path if (page) { path = `/${parsePath(page.requirePath).dirname}/${parsed.basename}` diff --git a/lib/utils/get-load-context.js b/lib/utils/get-load-context.js new file mode 100644 index 0000000000000..c51f912e642bd --- /dev/null +++ b/lib/utils/get-load-context.js @@ -0,0 +1,26 @@ +function getLoadContext (relativePagesPath) { + return ` +/* @flow weak */ +// This file is auto-written and used by Gatsby to require +// files from your \`--pagesPath\` directory. +module.exports = function (callback) { + let context = require.context( + './${relativePagesPath}', + true, + /(coffee|cjsx|jsx|js|markdown|md|html|json|yaml|toml)$/, + ) + if (module.hot) { + module.hot.accept(context.id, () => { + context = require.context( + './${relativePagesPath}', + true, + /(coffee|cjsx|jsx|js|markdown|md|html|json|yaml|toml)$/ + ) + return callback(context) + }) + } + return callback(context) +} + `.trim() +} +module.exports = getLoadContext diff --git a/lib/utils/glob-pages.js b/lib/utils/glob-pages.js index 55f53b08e6e90..97ef0c8307434 100644 --- a/lib/utils/glob-pages.js +++ b/lib/utils/glob-pages.js @@ -5,21 +5,21 @@ const debug = require('debug')('gatsby:glob') import pageFileTypes from './page-file-types' -function globQuery (directory) { +function globQuery (pagesPath) { const fileGlobQuery = pageFileTypes.map((type) => `*.${type}`) const joinedFileQuery = fileGlobQuery.join('|') - return `${directory}/pages/**/?(${joinedFileQuery})` + return `${pagesPath}/**/?(${joinedFileQuery})` } let globCache -function createCache (directory, callback) { +function createCache (pagesPath, callback) { const pagesData = [] - glob(globQuery(directory), null, (err, pages) => { + glob(globQuery(pagesPath), null, (err, pages) => { if (err) { return callback(err) } pages.forEach((page) => { - pagesData.push(buildPage(directory, page)) + pagesData.push(buildPage(pagesPath, page)) }) debug(`globbed ${pagesData.length} pages`) @@ -28,9 +28,9 @@ function createCache (directory, callback) { }) } -module.exports = function globPages (directory, callback) { +module.exports = function globPages (pagesPath, callback) { if (typeof globCache === 'undefined') { - createCache(directory, callback) + createCache(pagesPath, callback) } else { callback(null, globCache) } diff --git a/lib/utils/load-context.js b/lib/utils/load-context.js deleted file mode 100644 index f33346d987ac9..0000000000000 --- a/lib/utils/load-context.js +++ /dev/null @@ -1,13 +0,0 @@ -/* @flow weak */ -// This file is auto-written and used by Gatsby to require -// files from your pages directory. -module.exports = function (callback) { - let context = require.context('./pages', true, /(coffee|cjsx|jsx|js|markdown|md|html|json|yaml|toml)$/) // eslint-disable-line - if (module.hot) { - module.hot.accept(context.id, () => { - context = require.context('./pages', true, /(coffee|cjsx|jsx|js|markdown|md|html|json|yaml|toml)$/) // eslint-disable-line - return callback(context) - }) - } - return callback(context) -} diff --git a/lib/utils/post-build.js b/lib/utils/post-build.js index 9d36ea079c8f6..1954da72a2c67 100644 --- a/lib/utils/post-build.js +++ b/lib/utils/post-build.js @@ -12,7 +12,7 @@ import globPages from './glob-pages' module.exports = (program, cb) => { const directory = program.directory - return globPages(directory, (err, pages) => { + return globPages(program.pagesPath, (err, pages) => { debug('copying files') // Async callback to copy each file. const copy = function copyFile (file, callback) { @@ -21,7 +21,7 @@ module.exports = (program, cb) => { // rewritten to my-sweet-blog-post, we find that path rewrite so // our asset gets copied to the right directory. const parsed = parsePath(file) - const relativePath = path.relative(`${directory}/pages`, file) + const relativePath = path.relative(program.pagesPath, file) let oldDirectory = parsePath(relativePath).dirname let newPath = '' @@ -57,7 +57,7 @@ module.exports = (program, cb) => { // Copy static assets to public folder. const assetTypes = '*.jpg|*.jpeg|*.png|*.pdf|*.gif|*.ico|*.svg|*.pdf|*.txt|CNAME' - const globString = `${directory}/pages/**/?(${assetTypes})` + const globString = `${program.pagesPath}/**/?(${assetTypes})` return glob(globString, null, (e, files) => async.map(files, copy, (error, results) => cb(error, results) diff --git a/lib/utils/webpack.config.js b/lib/utils/webpack.config.js index 4458e1c647a08..64c85bd0eec25 100644 --- a/lib/utils/webpack.config.js +++ b/lib/utils/webpack.config.js @@ -227,7 +227,7 @@ module.exports = (program, directory, suppliedStage, webpackPort = 1500, routes test: /config\.toml/, loader: 'config', query: { - directory, + pagesPath: program.pagesPath, }, }) // Image loaders. @@ -417,9 +417,8 @@ module.exports = (program, directory, suppliedStage, webpackPort = 1500, routes } const config = new Config() - config.merge({ - context: `${directory}/pages`, + context: program.pagesPath, node: { __filename: true, },