Skip to content

Commit

Permalink
Webpack config refactor; CSS now generated with HTML (#253)
Browse files Browse the repository at this point in the history
* Build refactor; CSS generated with static step

* 'build-spa' -> 'build-javascript'

* Simplify build-javascript pass-through callback

* Split third stage into: build-css and build-html

Because webpack will always generate a final javascript file, the
'build-css' stage isn't as clean as I'd like it.
  • Loading branch information
scottnonnenberg authored and KyleAMathews committed May 8, 2016
1 parent 11b2bd9 commit a87cb38
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 63 deletions.
16 changes: 16 additions & 0 deletions lib/utils/build-css.js
Original file line number Diff line number Diff line change
@@ -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)
})
}
11 changes: 8 additions & 3 deletions lib/utils/static-generation.js → lib/utils/build-html.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
})
})
Expand Down
10 changes: 10 additions & 0 deletions lib/utils/build-javascript.js
Original file line number Diff line number Diff line change
@@ -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)
}
11 changes: 0 additions & 11 deletions lib/utils/build-production.js

This file was deleted.

35 changes: 21 additions & 14 deletions lib/utils/build.js
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
})
})
}

Expand Down
119 changes: 84 additions & 35 deletions lib/utils/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand All @@ -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`,
Expand All @@ -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.`)
}
Expand All @@ -75,32 +94,41 @@ 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'),
},
__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.`)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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']),
Expand All @@ -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
}
Expand Down

0 comments on commit a87cb38

Please sign in to comment.