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

Enable extension of webpack config by consumers #87

Merged
merged 5 commits into from Nov 24, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Expand Up @@ -188,7 +188,28 @@ module.exports = React.createClass({
})
```

### How to write your own loaders/wrappers
### How to use your own loaders

Create a `gatsby.config.js` in the root of your
project. `gatsby.config.js` exports a function which accepts a config
object and an environment string. The environment string will be one
of `serve`, `static` or `production`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be develop now. Plus we should point them to the default loaders somehow so they know what they're modifying.


Consider the following example which removes the default css loader
and replaces it with a loader that uses css-modules.

```javascript
modules.exports = function(config, env) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll probably want to introduce this by explaining we're using webpack-configurator so they can go there to learn more about what options are available..

config.removeLoader('css');
config.loader('css', function(cfg) {
cfg.test = /\.css$/;
cfg.loader = 'style!css?modules'
return cfg
})
});
```

### How to write your own wrappers
* Coming...

### Structure of a Gatsby site
Expand Down
4 changes: 3 additions & 1 deletion lib/utils/build-production.coffee
@@ -1,11 +1,13 @@
webpack = require 'webpack'
webpackConfig = require './webpack.config'
path = require 'path'

module.exports = (program, callback) ->
{relativeDirectory, directory} = program

#### Build production js.
compilerConfig = webpackConfig(program, directory, 'production')
webpack(compilerConfig).run (err, stats) ->
config = require(path.resolve(process.cwd(), './gatsby.config.js'))(compilerConfig, 'production');
webpack(config.resolve()).run (err, stats) ->
callback err, stats

7 changes: 5 additions & 2 deletions lib/utils/develop.js
Expand Up @@ -28,7 +28,9 @@ module.exports = function(program) {
var webpackPort = Math.round(Math.random() * 1000 + 1000);

var compilerConfig = webpackConfig(program, directory, 'develop', webpackPort);
var compiler = webpack(compilerConfig);
var config = require(path.resolve(process.cwd(), './gatsby.config.js'))(compilerConfig, 'develop');

var compiler = webpack(config.resolve());

var HTMLPath;
if (fs.existsSync(directory + "/html.cjsx") || fs.existsSync(directory + "/html.jsx")) {
Expand All @@ -39,7 +41,8 @@ module.exports = function(program) {
}

var htmlCompilerConfig = webpackConfig(program, directory, 'production', webpackPort);
webpackRequire(htmlCompilerConfig, require.resolve(HTMLPath), function(err, factory) {
var htmlConfig = require(path.resolve(process.cwd(), './gatsby.config.js'))(htmlCompilerConfig, 'production');
webpackRequire(htmlConfig.resolve(), require.resolve(HTMLPath), function(err, factory) {
if (err) {
console.log("Failed to require " + directory + "/html.jsx")
err.forEach(function(error) { console.log(error) })
Expand Down
5 changes: 4 additions & 1 deletion lib/utils/static-generation.coffee
Expand Up @@ -2,6 +2,7 @@ require('node-cjsx').transform()
webpack = require 'webpack'
globPages = require './glob-pages'
webpackConfig = require './webpack.config'
path = require 'path'

module.exports = (program, callback) ->
{relativeDirectory, directory} = program
Expand All @@ -11,8 +12,10 @@ module.exports = (program, callback) ->

#### Static site generation.
compilerConfig = webpackConfig(program, directory, 'static', null, routes)
console.log(compilerConfig)
config = require(path.resolve(process.cwd(), './gatsby.config.js'))(compilerConfig, 'static');

webpack(compilerConfig).run (err, stats) ->
webpack(config.resolve()).run (err, stats) ->
if err
return callback(err, stats)
if stats.hasErrors()
Expand Down
197 changes: 197 additions & 0 deletions lib/utils/webpack.config.js
@@ -0,0 +1,197 @@
var webpack = require('webpack');
var StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
var Config = require('webpack-configurator');

var gatsbyLib = /(gatsby.lib)/i;
var libDirs = /(node_modules|bower_components)/i;
var babelExcludeTest = function(absPath) {
var result = false;
if(absPath.match(gatsbyLib)) {
// There is a match, don't exclude this file.
result = false
} else if(absPath.match(libDirs)) {
// There is a match, do exclude this file.
result = true
} else {
result = false
}

return result
}

module.exports = function(program, directory, stage, webpackPort, routes) {
webpackPort = webpackPort || 1500;
routes = routes || [];
function output() {
switch(stage) {
case "develop":
return {
path: directory,
filename: 'bundle.js',
publicPath: `http://${program.host}:${webpackPort}/`
}
case "production":
return {
filename: "bundle.js",
path: directory + "/public"
}
case "static":
return {
path: directory + "/public",
filename: "bundle.js",
libraryTarget: 'umd'
}
}
}

function entry() {
switch(stage) {
case "develop":
return [
`${__dirname}/../../node_modules/webpack-dev-server/client?${program.host}:${webpackPort}`,
`${__dirname}/../../node_modules/webpack/hot/only-dev-server`,
`${__dirname}/web-entry`
]
case "production":
return [
`${__dirname}/web-entry`
]
case "static":
return [
`${__dirname}/static-entry`
]
}
}

function plugins() {
switch(stage) {
case "develop":
return [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify(process.env.NODE_ENV ? process.env.NODE_ENV : "development")
},
__PREFIX_LINKS__: program.prefixLinks
})
]
case "production":
return [
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()
]
case "static":
return [
new StaticSiteGeneratorPlugin('bundle.js', routes),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify(process.env.NODE_ENV ? process.env.NODE_ENV : "production")
},
__PREFIX_LINKS__: program.prefixLinks
})
]
}
}

function resolve() {
return {
extensions: ['', '.js', '.jsx', '.cjsx', '.coffee', '.json', '.less', '.toml', '.yaml'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does webpack-configurator make it easy to modify extensions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the object way

Using an object in merge will add the extensions values to the array.

config.merge({
    resolve: {
      extensions: ['ahhh', '.bbb']
    }
})

the function way

Using a function yields more control, but when I tried it it threw up on glob-pages later in the build process. That said, it did work and in the following example, it added ahhh and .bbb then removed ahhh.

    config.merge({
      resolve: {
        extensions: ['ahhh', '.bbb']
      }
    })
    config.merge(function(cfg) {
      cfg.resolve.extensions = _.without(cfg.resolve.extensions, 'ahhh');
      return cfg;
    })

Also, I think I've tracked down the issue in webpack configurator for the function-based merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR for the fix is here: lewie9021/webpack-configurator#10

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

modulesDirectories: [
directory,
`${__dirname}/../isomorphic`,
`${directory}/node_modules`,
"node_modules"
]
}
}

function devtool() {
switch(stage) {
case "develop":
case "static":
return "eval"
case "production":
return "source-map"
}
}

function module(config) {

// common config for every env
config.loader('cjsx',{ test: /\.cjsx$/, loaders: ['coffee', 'cjsx']});
config.loader('js',{
test: /\.jsx?$/,
exclude: babelExcludeTest,
loaders: ['babel']
});
config.loader('coffee',{ test: /\.coffee$/, loader: 'coffee' });
config.loader('md',{ test: /\.md$/, loader: 'markdown' });
config.loader('html',{ test: /\.html$/, loader: 'raw' });
config.loader('json',{ test: /\.json$/, loaders: ['json'] });
config.loader('toml',{ test: /^((?!config).)*\.toml$/, loaders: ['toml'] }); // Match everything except config.toml
config.loader('png',{ test: /\.png$/, loader: 'null' });
config.loader('jpg',{ test: /\.jpg$/, loader: 'null' });
config.loader('svg',{ test: /\.svg$/, loader: 'null' });
config.loader('ico',{ test: /\.ico$/, loader: 'null' });
config.loader('pdf',{ test: /\.pdf$/, loader: 'null' });
config.loader('txt',{ test: /\.txt$/, loader: 'null' });
config.loader('config',{ test: /config\.[toml|yaml|json]/, loader: 'config', query: {
directory: directory
} });

switch(stage) {
case "develop":
config.loader('css', { test: /\.css$/, loaders: ['style', 'css']});
config.loader('less', { test: /\.less/, loaders: ['style', 'css', 'less']});
config.loader('js', {}, (cfg) => {
console.log('cfg',cfg);
cfg.loaders.unshift('react-hot');
console.log(cfg)
return cfg;
})
return config;

case "static":
config.loader('css',{ test: /\.css$/, loaders: ['css']});
config.loader('less',{ test: /\.less/, loaders: ['css', 'less']});
return config

case "production":
config.loader('css',{ test: /\.css$/, loaders: ['style', 'css']});
config.loader('less',{ test: /\.less/, loaders: ['style', 'css', 'less']});

return config
}
}
var config = new Config();

console.log('loaders stage:', stage);
config.merge({
context: directory + "/pages",
node: {
__filename: true
},
entry: entry(),
debug: true,
devtool: devtool(),
output: output(),
resolveLoader: {
modulesDirectories: [
`${directory}/node_modules`,
`${__dirname}/../../node_modules`,
`${__dirname}/../loaders`
]
},
plugins: plugins(),
resolve: resolve()
});

return module(config);
}
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -55,6 +55,7 @@
"underscore": "^1.8.3",
"underscore.string": "^3.1.1",
"webpack": "^1.12.8",
"webpack-configurator": "^0.3.0",
"webpack-dev-server": "^1.12.1",
"webpack-require": "0.0.15"
},
Expand Down