Webpack 缩小分发文件问题

Webpack minified distribution file issue

首先我得说我是一个 webpack 新手,我已经使用这个很棒的工具大约 2 周了,除了这个我已经设法实现了我需要的一切。

事情是这样的:在我的公司,我们正试图将一组通用的输入、组件和通用 css 抽象到托管在单独存储库中的模块,以便它可以作为我们其他模块中的供应商, 它叫做 Mandioca。我们所有的应用程序都是使用 Angularjs 框架开发的,因此它是一个 angular 模块。

我将所有内容捆绑在一个包含所有 .js 文件的缩小文件中,并将其输出到名为 dist 的文件夹中。没什么大不了的。

当我尝试在任何其他模块中导入 mandioca 时会出现此问题。我收到此异常:TypeError: Failed to construct 'WebSocket': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

我认为这是缩小文件中的问题,因为当我停止在模块的依赖项上导入 Mandioca 时,错误消失了:

// Exception :(
angular.module('app', [
    'Mandioca',
    // (...other dependencies)
]);

// Everything OK
angular.module('app', [
    // (...other dependencies)
]);

我深入研究了 webpack 配置文档和 angular + webpack cookbook,发现了一些有趣的东西,但遗憾的是没有解决我的问题:

指定 externals:

externals: {
  angular: 'angular',
}

指定 output libraryTarget 选项:

config.output = {
  path: path.join(__dirname, distFolder),
  filename: (isBuild ? minJs : '[name].bundle.js'),
  libraryTarget: 'umd' // <--- here's the tweak
};

其他一些注意事项:

Mandioca 的 Webpack 文件:

// webpack stuff
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import WebpackNotifierPlugin from 'webpack-notifier';
// import CopyWebpackPlugin from 'copy-webpack-plugin';

// postcss
import rucksack from 'rucksack-css';
import cssnano from 'cssnano';
import nested from 'postcss-nested';
import mixins from 'postcss-mixins';
import simpleVars from 'postcss-simple-vars';
import cssnext from 'postcss-cssnext';
import postcssImport from 'postcss-import';

import vendors from './vendors.json';
import path from 'path';

export default function makeWebpackConfig(options) {
  const vendorsDir = path.join(__dirname, 'node_modules');
  const excludeVendors = /node_modules/;
  const distFolder = 'dist';
  const minJs = 'mandioca.min.js';
  const minCss = 'mandioca.min.css';
  const devEntry = './app/app.dev.js';
  const distEntry = './app/app.dist.js';
  const isTest = !!options.TEST;
  const isBuild = !!options.BUILD;
  const isDev = !isBuild && !!options.DEV;
  const isDevProd = isBuild && !!options.DEV;

  const getCssLoader = (build) => {
    let baseStr = 'css?sourceMap!postcss';

    return build ? ExtractTextPlugin.extract('style', baseStr) : 'style!' + baseStr;
  };

  const esLintPreLoader = {
    test: /\.js$/,
    loader: 'eslint',
    exclude: excludeVendors
  };

  const jsLoader = {
    test: /\.js$/,
    loaders: ['ng-annotate', 'babel'],
    exclude: excludeVendors
  };

  const cssLoader = {
    test: /\.css$/,
    loader: getCssLoader(isBuild),
    exclude: excludeVendors
  };

  const vendorsCssLoader = {
    test: /\.css$/,
    loader: 'style!css?sourceMap',
    include: excludeVendors
  };

  const filesLoader = {
    test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
    loader: 'file',
    exclude: excludeVendors
  };

  const htmlLoader = {
    test: /\.html$/,
    loaders: ['ngtemplate', 'html'],
    exclude: excludeVendors
  };

  const config = {
    resolve: {
      alias: {}
    },
    plugins: [],
    entry: {
      app: ((isBuild && !isDevProd) ? distEntry : devEntry),
      vendor: []
    },
    module: {},
    externals: {
      angular: 'angular',
    }
  };

  config.output = {
    path: path.join(__dirname, distFolder),
    filename: (isBuild ? minJs : '[name].bundle.js'),
    libraryTarget: 'umd'
  };

  if (!isBuild && (isDev || isDevProd)) {
    config.module.noParse = [];
    vendors.forEach((vendor) => {
      let vendorPath = path.resolve(vendorsDir, vendor);
      // config.module.noParse.push(vendorPath);
      config.entry.vendor.push(vendorPath);
      config.resolve.alias[vendor.split(path.sep)[0]] = vendorPath;
    });
  }

  if (!isTest) {
    // Reference: https://github.com/ampedandwired/html-webpack-plugin
    // Render index.html
    config.plugins.push(
      new HtmlWebpackPlugin({
        template: './index.html',
        inject: true,
        production: isBuild,
      }),
      new webpack.ProvidePlugin({
        moment: 'moment',
        R: 'ramda',
        CPF: 'cpf_cnpj'
      }),
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor',
        filename: (isBuild && !isDevProd) ? minJs : '[name].bundle.js',
      }),
      // Reference: https://github.com/Turbo87/webpack-notifier
      // Pops a notification on error
      new WebpackNotifierPlugin(),
      new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }})
    );
  }

  config.postcss = function(webp) {
    let cssnanoOpt = {
      discardUnused: false,
      zindex: false
    };
    let rucksackOpt = { autoprefixer: true };

    let devPlugins = [
      postcssImport({ addDependencyTo: webp }),
      mixins,
      nested,
      simpleVars,
      rucksack(rucksackOpt),
      cssnext
    ];
    let prodPlugins = [cssnano(cssnanoOpt)];

    let plugins;
    if (isBuild) {
      plugins = devPlugins;
    } else {
      plugins = devPlugins.concat(prodPlugins);
    }

    return plugins;
  };

  config.module.preLoaders = [esLintPreLoader];
  config.module.loaders = [jsLoader, cssLoader, htmlLoader, filesLoader];

  if (isBuild || isDevProd) {
    config.plugins.push(new ExtractTextPlugin(minCss));
  }

  if (isDevProd || isDev) {
    config.module.loaders.push(vendorsCssLoader);
  }

  return config;
}

我不知道,但也许这不是 webpack 的责任。无论如何,如果有任何信息可以让我摆脱这个障碍,我会非常高兴。

快速查看您的 webpack 配置,我发现 CommonsChunks 插件存在错误。您将生成的 CommonsChunks 文件命名为与输出条目文件相同的名称。因此输出文件(包含您的代码)正在被 CommonsChunks 文件替换。

如果您正在制作要分发的库,则不需要供应商文件,因此我会尝试删除 CommonsChunk 插件并查看它是否有效。