Skip to content
Snippets Groups Projects
webpack.config.js 8.62 KiB
Newer Older
  • Learn to ignore specific revisions
  • "use strict";
    
    /*eslint-env node */
    
    Tom Robinson's avatar
    Tom Robinson committed
    var webpack = require('webpack');
    var webpackPostcssTools = require('webpack-postcss-tools');
    
    
    var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
    
    Tom Robinson's avatar
    Tom Robinson committed
    var ExtractTextPlugin = require('extract-text-webpack-plugin');
    
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    var _ = require('underscore');
    var glob = require('glob');
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    
    function hasArg(arg) {
        var regex = new RegExp("^" + ((arg.length === 2) ? ("-\\w*"+arg[1]+"\\w*") : (arg)) + "$");
        return process.argv.filter(regex.test.bind(regex)).length > 0;
    }
    
    
    var SRC_PATH = __dirname + '/frontend';
    var BUILD_PATH = __dirname + '/resources/frontend_client';
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    
    // All JS files in frontend/src
    var JS_SRC = glob.sync(SRC_PATH + '/src/**/*.js');
    // All CSS files in frontend/src
    var CSS_SRC = glob.sync(SRC_PATH + '/src/**/*.css');
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    
    Tom Robinson's avatar
    Tom Robinson committed
    // Need to scan the CSS files for variable and custom media used across files
    // NOTE: this requires "webpack -w" (watch mode) to be restarted when variables change :(
    
    var isWatching = hasArg("-w") || hasArg("--watch");
    
        console.warn("Warning: in webpack watch mode you must restart webpack if you change any CSS variables or custom media queries");
    
    // default NODE_ENV to production unless -d or --debug is specified
    
    Tom Robinson's avatar
    Tom Robinson committed
    var NODE_ENV = process.env["NODE_ENV"] || (hasArg("-d") || (hasArg("--debug")) ? "development": "production");
    console.log("webpack env:", NODE_ENV)
    
    // Babel:
    var BABEL_CONFIG = {
    
    Tom Robinson's avatar
    Tom Robinson committed
        cacheDirectory: ".babel_cache",
    
        plugins: ['transform-decorators-legacy' ],
        presets: ['es2015', 'stage-0', 'react']
    };
    
    // CSS Next:
    var CSS_MAPS = { vars: {}, media: {}, selector: {} };
    
    Tom Robinson's avatar
    Tom Robinson committed
    CSS_SRC.map(webpackPostcssTools.makeVarMap).forEach(function(map) {
    
        for (var name in CSS_MAPS) _.extend(CSS_MAPS[name], map[name]);
    
    Tom Robinson's avatar
    Tom Robinson committed
    });
    
    var CSSNEXT_CONFIG = {
        features: {
            // pass in the variables and custom media we scanned for before
            customProperties: { variables: CSS_MAPS.vars },
            customMedia: { extensions: CSS_MAPS.media }
        },
        import: {
            path: ['resources/frontend_client/app/css']
        },
        compress: false
    };
    
    var CSS_CONFIG = {
        localIdentName: NODE_ENV !== "production" ? "[local]---[hash:base64:5]" : undefined,
        restructuring: false,
        compatibility: true
    }
    
    
    Tom Robinson's avatar
    Tom Robinson committed
    var config = module.exports = {
    
    Tom Robinson's avatar
    Tom Robinson committed
        // output a bundle for the app JS and a bundle for styles
        // eventually we should have multiple (single file) entry points for various pieces of the app to enable code splitting
    
    Tom Robinson's avatar
    Tom Robinson committed
        entry: {
    
            vendor: SRC_PATH + '/vendor.js',
    
    Tom Robinson's avatar
    Tom Robinson committed
            app: JS_SRC,
    
                SRC_PATH + '/vendor.css'
    
    Tom Robinson's avatar
    Tom Robinson committed
        },
    
    
    Tom Robinson's avatar
    Tom Robinson committed
        // output to "dist"
    
    Tom Robinson's avatar
    Tom Robinson committed
        output: {
    
            path: BUILD_PATH + '/app/dist',
    
            // NOTE: the filename on disk won't include "?[chunkhash]" but the URL in index.html generated by HtmlWebpackPlugin will:
    
            filename: '[name].bundle.js?[hash]',
    
            publicPath: '/app/dist/'
    
    Tom Robinson's avatar
    Tom Robinson committed
        },
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    
    Tom Robinson's avatar
    Tom Robinson committed
        module: {
            loaders: [
    
                {
                    test: /\.(js|jsx)$/,
                    exclude: /node_modules/,
                    loader: "babel",
                    query: BABEL_CONFIG
                },
                {
                    test: /\.(js|jsx)$/,
                    exclude: /node_modules|\.spec\.js/,
                    loader: 'eslint'
                },
    
    Tom Robinson's avatar
    Tom Robinson committed
                {
                    test: /\.(eot|woff2?|ttf|svg)$/,
                    loader: "file-loader"
                },
    
                {
                    test: /\.css$/,
    
                    loader: ExtractTextPlugin.extract("style-loader", "css-loader?" + JSON.stringify(CSS_CONFIG) + "!postcss-loader")
    
    Tom Robinson's avatar
    Tom Robinson committed
                /node_modules\/(angular|ace|moment|underscore)/ // doesn't include 'crossfilter', 'dc', and 'tether' due to use of 'require'
    
    Tom Robinson's avatar
    Tom Robinson committed
            ]
        },
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    
        resolve: {
    
            extensions: ["", ".webpack.js", ".web.js", ".js", ".jsx", ".css"],
    
    
                // angular
                'angular':              __dirname + '/node_modules/angular/angular.min.js',
                'angular-cookies':      __dirname + '/node_modules/angular-cookies/angular-cookies.min.js',
                'angular-resource':     __dirname + '/node_modules/angular-resource/angular-resource.min.js',
                'angular-route':        __dirname + '/node_modules/angular-route/angular-route.min.js',
                // angular 3rd-party
                'angular-cookie':       __dirname + '/node_modules/angular-cookie/angular-cookie.min.js',
                'angular-http-auth':    __dirname + '/node_modules/angular-http-auth/src/http-auth-interceptor.js',
                // ace
                'ace/ace':              __dirname + '/node_modules/ace-builds/src-min-noconflict/ace.js',
                'ace/ext-language_tools':__dirname+ '/node_modules/ace-builds/src-min-noconflict/ext-language_tools.js',
                'ace/mode-sql':         __dirname + '/node_modules/ace-builds/src-min-noconflict/mode-sql.js',
                'ace/snippets/sql':     __dirname + '/node_modules/ace-builds/src-min-noconflict/snippets/sql.js',
                // react
    
                'fixed-data-table':     __dirname + '/node_modules/fixed-data-table/dist/fixed-data-table.min.js',
                // misc
    
                'moment':               __dirname + '/node_modules/moment/min/moment.min.js',
    
                'tether':               __dirname + '/node_modules/tether/dist/js/tether.min.js',
    
                'underscore':           __dirname + '/node_modules/underscore/underscore-min.js',
                'd3':                   __dirname + '/node_modules/d3/d3.min.js',
    
                'crossfilter':          __dirname + '/node_modules/crossfilter/index.js',
    
                'dc':                   __dirname + '/node_modules/dc/dc.min.js',
    
                'humanize':             __dirname + '/node_modules/humanize-plus/dist/humanize.min.js'
    
    Tom Robinson's avatar
    Tom Robinson committed
        plugins: [
    
    Tom Robinson's avatar
    Tom Robinson committed
            // Separates out modules common to multiple entry points into a single common file that should be loaded first.
            // Not currently useful but necessary for code-splitting
    
            new CommonsChunkPlugin({
                name: 'vendor',
                minChunks: Infinity // (with more entries, this ensures that no other module goes into the vendor chunk)
            }),
    
    Tom Robinson's avatar
    Tom Robinson committed
            // Extracts initial CSS into a standard stylesheet that can be loaded in parallel with JavaScript
    
            // NOTE: the filename on disk won't include "?[chunkhash]" but the URL in index.html generated by HtmlWebpackPlugin will:
    
            new ExtractTextPlugin('[name].bundle.css?[contenthash]'),
            new HtmlWebpackPlugin({
    
                filename: '../../index.html',
                template: 'resources/frontend_client/index_template.html',
                inject: 'head'
            }),
            new webpack.DefinePlugin({
    
                'process.env': {
                    NODE_ENV: JSON.stringify(NODE_ENV)
                }
    
    Tom Robinson's avatar
    Tom Robinson committed
        ],
    
    Tom Robinson's avatar
    Tom Robinson committed
    
    
        postcss: function (webpack) {
            return [
                require("postcss-import")({ addDependencyTo: webpack }),
                require("postcss-url")(),
                require("postcss-cssnext")(CSSNEXT_CONFIG)
            ]
        }
    
    Tom Robinson's avatar
    Tom Robinson committed
        config.entry.app.unshift(
    
            'webpack-dev-server/client?http://localhost:8080',
            'webpack/hot/only-dev-server'
        );
    
    
        // suffixing with ".hot" allows us to run both `npm run build-hot` and `npm run test` or `npm run test-watch` simultaneously
    
        config.output.filename = "[name].hot.bundle.js?[hash]";
    
        // point the publicPath (inlined in index.html by HtmlWebpackPlugin) to the hot-reloading server
    
    Tom Robinson's avatar
    Tom Robinson committed
        config.output.publicPath = "http://localhost:8080" + config.output.publicPath;
    
        config.module.loaders.unshift({
            test: /\.jsx$/,
            exclude: /node_modules/,
            loaders: ['react-hot', 'babel?'+JSON.stringify(BABEL_CONFIG)]
        });
    
        // disable ExtractTextPlugin
    
        config.module.loaders[config.module.loaders.length - 1].loader = "style-loader!css-loader?" + JSON.stringify(CSS_CONFIG) + "!postcss-loader"
    
    Tom Robinson's avatar
    Tom Robinson committed
        config.plugins.unshift(
    
            new webpack.NoErrorsPlugin()
        );
    
    if (NODE_ENV === "development" || NODE_ENV === "hot") {
    
        // replace minified files with un-minified versions
    
    Tom Robinson's avatar
    Tom Robinson committed
        for (var name in config.resolve.alias) {
            var minified = config.resolve.alias[name];
    
            var unminified = minified.replace(/[.-\/]min\b/g, '');
    
            if (minified !== unminified && fs.existsSync(unminified)) {
    
    Tom Robinson's avatar
    Tom Robinson committed
                config.resolve.alias[name] = unminified;
    
    }
    
    if (NODE_ENV === "hot" || isWatching) {
        // enable "cheap" source maps in hot or watch mode since re-build speed overhead is < 1 second
        config.devtool = "eval-cheap-module-source-map";
    }
    
    if (NODE_ENV === "production") {
        config.devtool = "source-map";