服务器和客户端javascript的Webpack babel配置? [英] Webpack babel config for both server and client javascript?

查看:22
本文介绍了服务器和客户端javascript的Webpack babel配置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试弄清楚如何拥有一个单独的 webpack 配置文件,该文件可用于使用 es2015 预设转换服务器 (node.js) js 和客户端 js.目前我必须专门设置目标:'节点'"才能正确处理基于节点的文件.如果我不这样做,那么 webpack 会根据默认的目标:'web'"进行转换.然后它报告错误,因为正在导入的 'mysql' 模块显然不适用于 Web.

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 have to specifically set "target: 'node'" for it to correctly process node-based files. If I don't, then webpack does the transformation based on the default "target: 'web'". It then reports errors because the 'mysql' module being imported clearly won't work for web.

如何将两者统一到同一个配置文件中,以便分别转换服务器和客户端 js?还是我完全需要单独的配置?

How can I unify both into the same config file so that server and client js will be transformed separately? Or do I need separate configs entirely?

示例 webpack.config.js

Sample webpack.config.js

'use strict';

var path = require('path');
var webpack = require('webpack');

module.exports = {
  target: 'node',
  resolve: {
    root: path.resolve(__dirname),
    extensions: ['', '.js']
  },
  entry: [
    'babel-polyfill',
    './index.js',
  ],
  output: {
    filename: 'bundle.js'       
  },
  module: {
    loaders: [
      {
        test: /.js$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: ['es2015']
        }
      }
    ]
  }
};

示例js代码

import 'babel-polyfill';
import mysql from 'mysql';

class Test {
  constructor () {

  }

  get read () {

  }
};

推荐答案

Webpack 可以同时传递多个配置进行处理.只需返回一组配置对象即可.

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
  },
];

额外提示:如果您使用 .babel.js 作为配置文件的扩展名,Webpack 将通过 Babel 为您运行它,这允许您在 Webpack 配置中使用 ES6.

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.

奖励:下面的代码片段

// 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',
                },
            ],
        },
    },
];

这是我们在我们的一个站点中使用的配置,其中包含部分共享的代码库和部分共享的资产.它由三个 Webpack 构建合二为一:

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:

  • 浏览器
  • 服务器资产(图像/字体/...将在服务器生成的 HTML 中引用)
  • 服务器代码(节点)

服务器代码有一些特殊的属性:

The server code has a few special properties:

  • target: 'node'(Webpack 需要这个)
  • output.libraryTarget: 'commonjs'(让 Webpack 将 commonjs 用于非捆绑库)
  • externals: [/^(?!.|/).+/i, ] (使 Webpack 不会在 node_modules 中捆绑任何东西,或者任何不是相对路径的东西(从./)
  • 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 /)

这种组合使得 Webpack 只处理自己的代码,通过 require 访问其他模块和库.这意味着您使用本机绑定的依赖项不会被破坏,因为它们不会被捆绑.

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.

这篇关于服务器和客户端javascript的Webpack babel配置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆