Webpack babel config for both server and client javascript?

后端 未结 1 1195
渐次进展
渐次进展 2020-12-15 19:43

I\'m trying to figure out how to have a single webpack config file that works for transforming both server (node.js) js and client js with the es2015 preset. Currently I hav

相关标签:
1条回答
  • 2020-12-15 20:03

    You can pass multiple configs for Webpack to process at the same time. Simply return an array of configuration objects.

    export default [
      { 
        // config 1 here
      },
      {
        // config 2 here
      },
    ];
    

    Extra tip: if you use .babel.js as extension for your config file, Webpack will run it through Babel for you, which allows you to use ES6 in your Webpack config.

    Bonus: the snippet below

    // Source: https://gist.github.com/Ambroos/f23d517a4261e52b4591224b4c8df826
    
    import webpack from 'webpack';
    import path from 'path';
    
    import CleanPlugin from 'clean-webpack-plugin';
    import ExtractTextPlugin from 'extract-text-webpack-plugin';
    import AssetsPlugin from 'assets-webpack-plugin';
    import CompressionPlugin from 'compression-webpack-plugin';
    import autoprefixer from 'autoprefixer';
    import rucksack from 'rucksack-css';
    import cssnano from 'cssnano';
    import moment from 'moment';
    
    const sharedPlugins = [
        new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /nl/),
        new webpack.optimize.AggressiveMergingPlugin({}),
        new webpack.optimize.OccurenceOrderPlugin(true),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                drop_console: true,
                screw_ie8: true,
                sequences: true,
                properties: true,
                dead_code: true,
                drop_debugger: true,
                conditionals: true,
                comparisons: true,
                evaluate: true,
                booleans: true,
                loops: true,
                unused: true,
                if_return: true,
                join_vars: true,
                cascade: true,
                negate_iife: true,
                hoist_funs: true,
                warnings: false,
            },
            mangle: {
                screw_ie8: true,
            },
            output: {
                screw_ie8: true,
                preamble: '/* Website - ' + moment().format() + ' */',
            },
        }),
    ];
    
    const sharedServerPlugins = [
        new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /nl/),
        new webpack.optimize.AggressiveMergingPlugin({}),
        new webpack.optimize.OccurenceOrderPlugin(true),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                drop_console: false,
                screw_ie8: true,
                sequences: true,
                properties: true,
                dead_code: true,
                drop_debugger: false,
                conditionals: true,
                comparisons: true,
                evaluate: true,
                booleans: true,
                loops: true,
                unused: true,
                if_return: true,
                join_vars: true,
                cascade: true,
                negate_iife: true,
                hoist_funs: true,
                warnings: false,
            },
            mangle: {
                screw_ie8: true,
            },
            output: {
                screw_ie8: true,
                preamble: '/* Website - ' + moment().format() + ' */',
            },
        }),
    ];
    
    const PATHS = {
        build: path.resolve(__dirname, '..', 'build'),
        sourcemaps: path.resolve(__dirname, '..', 'build', 'sourcemaps'),
        browserSource: path.resolve(__dirname, '..', 'src', 'browser', 'index.js'),
        browserBuild: path.resolve(__dirname, '..', 'build', 'browser'),
        serverSource: path.resolve(__dirname, '..', 'src', 'server', 'index.js'),
        serverAssetsSource: path.resolve(__dirname, '..', 'src', 'server', 'assets', 'index.js'),
        serverBuild: path.resolve(__dirname, '..', 'build', 'server'),
    };
    
    export default [
        // Browser
        {
            entry: { browser: PATHS.browserSource },
            output: {
                path: PATHS.browserBuild,
                filename: 's/[chunkhash].js',
                chunkFilename: 's/async-[chunkhash].js',
                publicPath: '/',
                sourceMapFilename: '../sourcemaps/browser/[file].map',
            },
            devtool: 'hidden-source-map',
            plugins: [
                new AssetsPlugin({
                    prettyPrint: true,
                    path: path.resolve(PATHS.build, 'browserAssets'),
                    filename: 'index.js',
                    processOutput: assets => `module.exports = ${JSON.stringify(assets, null, '    ')};`,
                }),
                new CleanPlugin([PATHS.browserBuild, PATHS.sourcemaps], path.resolve(PATHS.build, 'browserAssets')),
                new ExtractTextPlugin('s/[contenthash].css'),
                new CompressionPlugin({
                    asset: '{file}.gz',
                    algorithm: 'gzip',
                    regExp: /\.js$|\.html$|\.css$|\.svg$|\.eot$|\.xml$/,
                    threshold: 1400,
                    minRation: 0.8,
                }),
                new webpack.DefinePlugin({
                    'process.env': {
                        NODE_ENV: JSON.stringify('production'),
                        WEBPACK_ENV: JSON.stringify('browser'),
                        APP_ENV: (process.env.APP_ENV && JSON.stringify(process.env.APP_ENV)) || undefined,
                    },
                }),
            ].concat(sharedPlugins),
            externals: [
                { browserConfig: 'var websiteBrowserConfig' },
                { programs: 'var programs' },
            ],
            module: {
                loaders: [
                    {
                        test: /\.jsx?$/,
                        exclude: /node_modules/,
                        loader: 'babel',
                    },
                    {
                        test: /\.json$/,
                        loader: 'json',
                    },
                    {
                        test: /\.scss$/,
                        loader: ExtractTextPlugin.extract(
                            'style',
                            [
                                'css?importLoaders=2&localIdentName=css-module-[hash:base64]',
                                'postcss',
                                'sass',
                            ]
                        ),
                    },
                    {
                        test: /\.(gif|png|jpe?g|svg|ico)$/i,
                        loaders: [
                            'url?limit=1400&name=s/i/[sha512:hash:base64:16].[ext]',
                            'image-webpack?bypassOnDebug',
                        ],
                    },
                    {
                        test: /isotope\-|fizzy\-ui\-utils|desandro\-|masonry|outlayer|get\-size|doc\-ready|eventie|eventemitter/,
                        loader: 'imports?define=>false&this=>window',
                    },
                    {
                        test: /flickity/,
                        loader: 'imports?define=>false&this=>window',
                    },
                    {
                        test: /node_modules\/unipointer/,
                        loader: 'imports?define=>undefined',
                    },
                ],
            },
            postcss: () => {
                return [rucksack, autoprefixer, cssnano];
            },
        },
    
        // Server assets
        {
            entry: { assets: PATHS.serverAssetsSource },
            target: 'node',
            output: {
                path: PATHS.browserBuild,
                libraryTarget: 'commonjs',
                filename: '../serverAssets/index.js',
                publicPath: '/',
            },
            plugins: [
                // assetsWriter,
                new CompressionPlugin({
                    asset: '{file}.gz',
                    algorithm: 'gzip',
                    regExp: /\.js$|\.html$|\.css$|\.svg$|\.eot$|\.xml$/,
                    threshold: 1400,
                    minRation: 0.8,
                }),
                new webpack.DefinePlugin({
                    'process.env': {
                        NODE_ENV: JSON.stringify('production'),
                        WEBPACK_ENV: JSON.stringify('assets'),
                        APP_ENV: (process.env.APP_ENV && JSON.stringify(process.env.APP_ENV)) || undefined,
                    },
                }),
            ].concat(sharedPlugins),
            module: {
                loaders: [
                    {
                        test: /\.jsx?$/,
                        exclude: /node_modules/,
                        loader: 'babel',
                    },
                    {
                        test: /\.json$/,
                        loader: 'json',
                    },
                    {
                        test: /\.(gif|png|jpe?g|svg|ico)$/i,
                        loaders: [
                            'url?limit=1400&name=s/i/[sha512:hash:base64:16].[ext]',
                            'image-webpack?bypassOnDebug',
                        ],
                    },
                ],
            },
        },
    
        // Server
        {
            entry: PATHS.serverSource,
            target: 'node',
            output: {
                path: PATHS.build,
                libraryTarget: 'commonjs',
                filename: 'server/server.js',
                publicPath: '/s/',
                sourceMapFilename: 'sourcemaps/browser/[file].map',
            },
            externals: [
                { serverAssets: '../serverAssets/index.js' },
                { browserAssets: '../browserAssets/index.js' },
                { vrtConfig: '../../env_vars.js' },
                /^(?!\.|\/).+/i,
                /webpack-assets\.json/,
            ],
            plugins: [
                new CleanPlugin(PATHS.serverBuild),
                new webpack.DefinePlugin({
                    'process.env': {
                        NODE_ENV: JSON.stringify('production'),
                        WEBPACK_ENV: JSON.stringify('server'),
                        APP_ENV: (process.env.APP_ENV && JSON.stringify(process.env.APP_ENV)) || undefined,
                    },
                }),
            ].concat(sharedServerPlugins),
            node: {
                __dirname: false,
                __filename: false,
            },
            module: {
                loaders: [
                    {
                        test: /\.jsx?$/,
                        exclude: /node_modules/,
                        loader: 'babel',
                    },
                    {
                        test: /\.json$/,
                        loader: 'json',
                    },
                ],
            },
        },
    ];

    That is the config we use in one of our sites with a partially shared codebase, and partially shared assets. It consists of three Webpack builds in one:

    • Browser
    • Server assets (images/fonts/... that will be referenced in server-generated HTML)
    • Server code (Node)

    The server code has a few special properties:

    • target: 'node' (Webpack needs this)
    • output.libraryTarget: 'commonjs' (makes Webpack use commonjs for unbundled libs)
    • externals: [ /^(?!\.|\/).+/i, ] (makes Webpack not bundle anything in node_modules, or anything that is not a relative path (starting with . or /)

    This combination makes Webpack only process your own code, and access other modules and libraries through require. Which means your dependencies using native bindings won't break as they won't be bundled.

    0 讨论(0)
提交回复
热议问题