electrodejs / electrode-archetype-react-component

Electrode flavored react component archetype
Other
88 stars 8 forks source link

Feature: Describe how to override/enhance webpack config. #12

Open jspears opened 8 years ago

jspears commented 8 years ago

Not clear from the readme.

My guess is it would be similar to how .babelrc is overwritten

project/ /src /webpack.config.js

exports.module = require('./node_modules/electrode-archetype-react-component/config/webpack/webpack.config');

But looking at the gulp file does not seem like this is how it would work.

wmertens commented 8 years ago

I've had success with a base config that creates a complete webpack config given some simple configuration parameters, and then letting override functions change it at will before passing it to webpack.

Secret sauce trick is to canonicalize loader configuration (always arrays of include etc) and add tag: "foo" to the loader related to "foo". This lets the override fn easily find loaders for adding query parameters or replacing it for e.g. css text extraction. The tags need to be removed again when using webpack v2.

configuration includes "server side", "hot", "production", extensions per type, max. inline size for the url loader etc.

khalidsalomao commented 8 years ago

@wmertens Could you post an example of how you overwritten the webpack config file? I am trying to enable sass support...

Antibioticvz commented 8 years ago

@khalidsalomao How is it going with the sass support?

khalidsalomao commented 8 years ago

@Antibioticvz no progress as far as I know :slightly_smiling_face:

@jspears @ananavati could you post an example? Is there a callback to modify the webpack configuration?

wmertens commented 8 years ago

example (just snippets):

const makeBase = ({isServer, isProd, entry, devtool, prerender}) => {
    const isClient = !isServer
    const {
        paths,
        webpack: {
            alias: origAlias, use, extensions, defines, publicPath, loaders: extraLoaders,
        },
    } = config.base
    let postcss

    // Remember, loaders apply from the last to the first, on every match
    const loaders = [
        {
            tag: 'json',
            test: hasExt(extensions.json),
            loader: 'json',
        },
// etc
        ...extraLoaders.map(applyPathsToLoader(paths)),
    ]

    // Canonicalize on .loaders for post-processing
    for (const l of loaders) {
        // Make loaders, include and exclude always arrays for easy patching
        if (l.loader) {
            l.loaders = l.loader.split('!')
            delete l.loader
        }
        if (l.exclude) {
            if (!Array.isArray(l.exclude)) {
                l.exclude = [l.exclude]
            }
        } else {
            l.exclude = []
        }
        if (l.include) {
            if (!Array.isArray(l.include)) {
                l.include = [l.include]
            }
        }
    }
    // Use fake-style on the server
    if (isServer) {
        for (const l of loaders) {
            if (l.loaders && l.loaders[0] === 'style') {
                l.loaders[0] = `fake-style`
            }
        }
    }
// make config and return it
}

and then in the app's production config, get the base and adjust for your needs:

const cfg = makeBase({
    isProd: true,
    entry: {
        app: [
            'babel-polyfill',
            'base/client',
        ],
        vendor: [
            'react',
            'react-dom',
        ],
    },
})

for (const l of cfg.module.loaders) {
    if (l.loaders && l.loaders[0] === 'style') {
        l.loaders = [ExtractTextPlugin.extract('fake-style', l.loaders.slice(1))]
    }
}
cfg.module.loaders.find(l => l.tag === 'assets').exclude = config.base.paths.icons
cfg.plugins = [
    ...cfg.plugins,
    new ExtractTextPlugin('[name].css'),
    new webpack.optimize.CommonsChunkPlugin({
        names: ['vendor', 'manifest'],
        minChunks: Infinity,
    }),
    new webpack.optimize.AggressiveMergingPlugin(),
    new webpack.optimize.MinChunkSizePlugin({minChunkSize: 15000}),
    new webpack.optimize.UglifyJsPlugin({compressor: {warnings: false}, comments: /(?:)/}),
    new AssetsPlugin({path: paths.build, filename: 'assets.json', includeManifest: true}),
]

Note that this is in my own project, not using Electrode yet but will in the near future. I was re-inventing Electrode all by myself :)

maximblack commented 8 years ago

Fast hack for enabling custom webpack.config.js: https://gist.github.com/anonymous/819cb2f5c9cbb8fd721c8d981e18680e