diff --git a/lib/utils/build-css.js b/lib/utils/build-css.js new file mode 100644 index 0000000000000..08d445c1e7138 --- /dev/null +++ b/lib/utils/build-css.js @@ -0,0 +1,16 @@ +import webpack from 'webpack' +import webpackConfig from './webpack.config' +import fs from 'fs' + +module.exports = (program, callback) => { + const { directory } = program + + const compilerConfig = webpackConfig(program, directory, 'build-css') + + return webpack(compilerConfig.resolve()).run((err, stats) => { + // We don't want any javascript produced by this step in the process. + fs.unlinkSync(`${directory}/public/bundle-for-css.js`) + + return callback(err, stats) + }) +} diff --git a/lib/utils/static-generation.js b/lib/utils/build-html.js similarity index 67% rename from lib/utils/static-generation.js rename to lib/utils/build-html.js index 229204ff89620..7b1354a86ef58 100644 --- a/lib/utils/static-generation.js +++ b/lib/utils/build-html.js @@ -2,17 +2,18 @@ require('node-cjsx').transform() import webpack from 'webpack' import globPages from './glob-pages' import webpackConfig from './webpack.config' -const debug = require('debug')('gatsby:static') +import fs from 'fs' +const debug = require('debug')('gatsby:html') module.exports = (program, callback) => { const { directory } = program globPages(directory, (err, pages) => { - debug('generating static site') + debug('generating static HTML') const routes = pages.filter((page) => page.path).map((page) => page.path) // Static site generation. - const compilerConfig = webpackConfig(program, directory, 'static', null, routes) + const compilerConfig = webpackConfig(program, directory, 'build-html', null, routes) webpack(compilerConfig.resolve()).run((e, stats) => { if (e) { @@ -21,6 +22,10 @@ module.exports = (program, callback) => { if (stats.hasErrors()) { return callback(`Error: ${stats.toJson().errors}`, stats) } + + // A temp file required by static-site-generator-plugin + fs.unlinkSync(`${directory}/public/render-page.js`) + return callback(null, stats) }) }) diff --git a/lib/utils/build-javascript.js b/lib/utils/build-javascript.js new file mode 100644 index 0000000000000..66a889f7b6bec --- /dev/null +++ b/lib/utils/build-javascript.js @@ -0,0 +1,10 @@ +import webpack from 'webpack' +import webpackConfig from './webpack.config' + +module.exports = (program, callback) => { + const { directory } = program + + const compilerConfig = webpackConfig(program, directory, 'build-javascript') + + return webpack(compilerConfig.resolve()).run(callback) +} diff --git a/lib/utils/build-production.js b/lib/utils/build-production.js deleted file mode 100644 index 6163c6b5f22b1..0000000000000 --- a/lib/utils/build-production.js +++ /dev/null @@ -1,11 +0,0 @@ -import webpack from 'webpack' -import webpackConfig from './webpack.config' - -module.exports = (program, callback) => { - const { directory } = program - - // Build production js. - const compilerConfig = webpackConfig(program, directory, 'production') - - return webpack(compilerConfig.resolve()).run((err, stats) => callback(err, stats)) -} diff --git a/lib/utils/build.js b/lib/utils/build.js index 78fc19afb2e6e..9c55ea242cc5c 100644 --- a/lib/utils/build.js +++ b/lib/utils/build.js @@ -1,5 +1,6 @@ -import generateStaticPages from './static-generation' -import buildProductionBundle from './build-production' +import buildCSS from './build-css' +import buildHTML from './build-html' +import buildProductionBundle from './build-javascript' import postBuild from './post-build' import globPages from './glob-pages' import toml from 'toml' @@ -62,7 +63,7 @@ function bundle (program, callback) { } function html (program, callback) { - console.log('Generating static html pages') + console.log('Generating static HTML/CSS') const directory = program.directory let config @@ -73,19 +74,25 @@ function html (program, callback) { callback(error) } - generateStaticPages(program, (error) => { - if (error) { - console.log('failed at generating static html pages') - return callback(error) + buildCSS(program, (cssError) => { + if (cssError) { + console.log('Failed at generating styles.css') + return callback(cssError) } - // If we're not generating a SPA, go directly to post build steps - if (config.noProductionJavascript) { - post(program, callback) - } else { - bundle(program, callback) - } - return true + return buildHTML(program, (htmlError) => { + if (htmlError) { + console.log('Failed at generating HTML') + return callback(htmlError) + } + + // If we're not generating javascript, go directly to post build steps + if (config.noProductionJavascript) { + return post(program, callback) + } else { + return bundle(program, callback) + } + }) }) } diff --git a/lib/utils/webpack.config.js b/lib/utils/webpack.config.js index a61e162f1709c..6c99c3e69dd6c 100644 --- a/lib/utils/webpack.config.js +++ b/lib/utils/webpack.config.js @@ -15,6 +15,12 @@ try { } } +// Four stages: +// 1) develop: for `gatsby develop` command, hot reload and CSS injection into page +// 2) build-css: build styles.css file +// 3) build-html: build all HTML files +// 4) build-javascript: Build bundle.js for Single Page App in production + module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => { debug(`Loading webpack config for stage "${stage}"`) function output () { @@ -25,13 +31,22 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => filename: 'bundle.js', publicPath: `http://${program.host}:${webpackPort}/`, } - case 'static': + case 'build-css': + // Webpack will always generate a resultant javascript file. + // But we don't want it for this step. Deleted by build-css.js. return { path: `${directory}/public`, - filename: 'bundle.js', + filename: 'bundle-for-css.js', + } + case 'build-html': + // A temp file required by static-site-generator-plugin. See plugins() below. + // Deleted by build-html.js, since it's not needed for production. + return { + path: `${directory}/public`, + filename: 'render-page.js', libraryTarget: 'umd', } - case 'production': + case 'build-javascript': return { filename: 'bundle.js', path: `${directory}/public`, @@ -48,14 +63,18 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => require.resolve('webpack-hot-middleware/client'), `${__dirname}/web-entry`, ] - case 'production': + case 'build-css': + return { + main: `${__dirname}/web-entry`, + } + case 'build-html': + return { + main: `${__dirname}/static-entry`, + } + case 'build-javascript': return [ `${__dirname}/web-entry`, ] - case 'static': - return [ - `${__dirname}/static-entry`, - ] default: throw new Error(`The state requested ${stage} doesn't exist.`) } @@ -75,25 +94,19 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => __PREFIX_LINKS__: program.prefixLinks, }), ] - case 'production': + case 'build-css': return [ - // Moment.js includes 100s of KBs of extra localization data - // by default in Webpack that most sites don't want. - // This line disables that. - new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV ? process.env.NODE_ENV : 'production'), }, __PREFIX_LINKS__: program.prefixLinks, }), - new webpack.optimize.DedupePlugin(), new ExtractTextPlugin('styles.css'), - new webpack.optimize.UglifyJsPlugin(), ] - case 'static': + case 'build-html': return [ - new StaticSiteGeneratorPlugin('bundle.js', routes), + new StaticSiteGeneratorPlugin('render-page.js', routes), new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV ? process.env.NODE_ENV : 'production'), @@ -101,6 +114,21 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => __PREFIX_LINKS__: program.prefixLinks, }), ] + case 'build-javascript': + return [ + // Moment.js includes 100s of KBs of extra localization data + // by default in Webpack that most sites don't want. + // This line disables that. + new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(process.env.NODE_ENV ? process.env.NODE_ENV : 'production'), + }, + __PREFIX_LINKS__: program.prefixLinks, + }), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.UglifyJsPlugin(), + ] default: throw new Error(`The state requested ${stage} doesn't exist.`) } @@ -135,9 +163,9 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => switch (stage) { case 'develop': return 'eval' - case 'static': + case 'build-html': return false - case 'production': + case 'build-javascript': return 'source-map' default: return false @@ -266,22 +294,7 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => }) return config - case 'static': - config.loader('css', { - test: /\.css$/, - loaders: ['css'], - }) - config.loader('less', { - test: /\.less/, - loaders: ['css', 'less'], - }) - config.loader('sass', { - test: /\.(sass|scss)/, - loaders: ['css', 'sass'], - }) - return config - - case 'production': + case 'build-css': config.loader('css', { test: /\.css$/, loader: ExtractTextPlugin.extract(['css', 'postcss']), @@ -307,6 +320,42 @@ module.exports = (program, directory, stage, webpackPort = 1500, routes = []) => }) return config + case 'build-html': + // We don't deal with CSS at all when building the HTML. + // The 'null' loader is used to prevent 'module not found' errors. + + config.loader('css', { + test: /\.css$/, + loader: 'null', + }) + config.loader('less', { + test: /\.less/, + loader: 'null', + }) + config.loader('sass', { + test: /\.(sass|scss)/, + loader: 'null', + }) + return config + + case 'build-javascript': + // We don't deal with CSS at all when building the javascript. + // The 'null' loader is used to prevent 'module not found' errors. + + config.loader('css', { + test: /\.css$/, + loader: 'null', + }) + config.loader('less', { + test: /\.less/, + loader: 'null', + }) + config.loader('sass', { + test: /\.(sass|scss)/, + loader: 'null', + }) + return config + default: return config }