在 webpack react 应用程序中创建一个测试入口点

create a test entry point in webpack react application

tldr:我能够 require 制作应用程序的所有内容 运行,但是如果我 require 来自测试(在应用程序中 - 请参阅下面的目录结构)文件,整个依赖链中断。

我在require-ing 从我的 app/test 目录(在我的 webpack React.js 应用程序中)的组件中遇到一些困难 require -从 /app 文件夹中的任何其他文件下载。这是目录结构

app
  /components/checkout.jsx
  /components/button.jsx
  /test/test.js 
  index.jsx  
dist
node_modules
webpack.config.js
package.json

在我的 webpack.config.js 中,我将它设置为像这样为我的 React 应用程序使用 jsx-loader

entry: {
   app: "./app/index"
},
module: {
   loaders: [
        {
             test: /\.jsx$/,
             loader: 'jsx-loader?insertPragma=React.DOM&harmony',
     }
  ]
},
resolve: {
 extensions: ['', '.js', '.jsx']
}

这允许我要求以扩展名 .jsx 结尾的文件。例如,在 /app/index.jsx 中,我需要 /app/components/checkout.jsx 通过

 var Checkout = require('./components/Checkout')

/app/components/checkout.jsx 里面,我需要按钮

var Button = require('./components/Button')

所以当我从 index.jsx 请求 Checkout 时,它可以毫无问题地处理按钮的请求。

然而,从app/test/test.js,我

var Checkout = require('../components/Checkout')

webpack 找不到 Checkout 组件。当我在 webpack 开发服务器中查看测试时,它没有显示已查找 .jsx 文件扩展名。它搜索

 app/components/Checkout
 app/components/Checkout.webpack.js
 app/components/Checkout.web.js
 app/components/Checkout.js
 app/components/Checkout.json

因此,我尝试像这样使用 jsx-loader内联

 var Checkout = require(jsx-loader!'../components/Checkout')

从测试目录,webpack 现在可以找到该文件,但它会抛出一个错误,指出它无法解析 Checkout requires 的按钮。换句话说,当我使用 app/test 文件夹中的 require 时,整个依赖链不同步。

如何更改我的 webpack.config.js 以便能够在具有此目录结构的测试中需要应用程序文件,或者更一般地说,如何配置 webpack 以在测试中需要应用程序文件?

更新

项目结构

/app
  /test/test.js
  /index.jsx
  /components/checkout.jsx (and button.jsx)
/dist
/node_modules
package.json
webpack.config.js

整个 webpack 配置

var webpack = require('webpack');
module.exports = {
    context: __dirname + "/app",
    entry: {
      vendors: ["d3", "jquery"],
      app: "index"
      // app: "./app/index"

      },
    output: {
        path: './dist',
        filename: 'bundle.js', //this is the default name, so you can skip it
        //at this directory our bundle file will be available
        //make sure port 8090 is used when launching webpack-dev-server
        publicPath: 'http://localhost:8090/assets/'
    },

    externals: {
        //don't bundle the 'react' npm package with our bundle.js
        //but get it from a global 'React' variable

        'react': 'React'
        // 'd3': 'd3'
    },
    resolve: {
        modulesDirectories: ['app', 'node_modules'],
        extensions: ['', '.js', '.jsx'],
        resolveLoader: { fallback: __dirname + "/node_modules" },
        root: ['/app', '/test']
    },
    module: {
        loaders: [
            {
              test: /\.jsx$/, 
              loader: 'jsx-loader?insertPragma=React.DOM&harmony',
            }
        ]
    },

    plugins: [
    // definePlugin,
    new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js')

    ]
}

一个可能的解决方案是始终要求文件扩展名:

var Checkout = require('./components/Checkout.jsx')

我猜可能是因为将 "test" 设置为根目录。但直到你分享你的代码才清楚。你能给我一个 link 到 GitHub 的回购或什么的吗?

我看到你在使用和声参数,我可以假设你在使用 es6 吗?

如果是这样的话,我之前遇到过这个问题,对我来说问题是文件被添加到 es5 中,作为 es6 没有经过蜜蜂转换,由 jsx-loader / babel-loader 添加到 es5。

所以我需要补充:

preLoaders: [{
    test: [/\.jsx$/, /\.js$/],
    include: // modules here
    loaders: ['babel-loader?optional[]=runtime']
}]

但这并不能解释为什么这只对您的测试失败。也许你可以详细说明当你 运行 你的测试时 运行ned 是什么 但现在我仍然假设你使用 es6,

如果你不是上述情况,尝试安装本地版本的webpack,并在你的本地目录和你的应用程序文件夹中寻找它

(resolveLoader: { root: path.join(__dirname, "node_modules") })

希望这个帮助ps

编辑:ps 查看你的配置,resolveLoader 不应该是你的 resolve 的一部分,在我使用的另一个 webpack 设置中,我有以下设置 用于解决:

resolve: {
  extensions: ['', '.js', '.jsx', '.json'],
  modulesDirectories: ['node_modules', 'node_modules/vl_tooling/node_modules']
},
resolveLoader: {
  modulesDirectories: ['node_modules', 'node_modules/vl_tooling/node_modules']
},

我为 运行 React 测试设置了单独的 gulp 任务,也许你可以重用这个想法:

karma.js

var karma = require('gulp-karma'),
  _ = require('lodash'),
  Promise = require('bluebird'),
  plumber = require('gulp-plumber'),
  path = require('path'),
  webpack = require('gulp-webpack'),
  named = require('vinyl-named');

module.exports = function (gulp, options) {
  var root = path.join(options.cwd, 'app'),
    extensions = ['', '.js', '.jsx'],
    modulesDirectories = ['node_modules'];

  gulp.task('karma', ['karma:build'], function () {
    return runAllTests(gulp, options);
  });

  gulp.task('karma:build', function() {
    var optionsForTests = _.merge({
      ignore: ['**/node_modules/**']
    }, options);

    return gulp.src(['**/__tests__/*.js'], optionsForTests).
      pipe(named(function(file){
        // name file bundle.js
        return 'bundle';
      })).
      pipe(webpack({
        module: {
          loaders: [
              // runtime option adds Object.assign support
              { test: /\.(js|jsx)$/, loader: 'babel-loader?optional[]=runtime', exclude: /node_modules/},
              { test: /\.(sass|scss)$/, loader: 'css-loader!sass-loader'},
              { test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/, loader: 'url-loader'},
              { test: /\.(ttf|eot)$/, loader: 'file-loader'},
              { test: /sinon.*\.js$/, loader: 'imports?define=>false' } // hack due to https://github.com/webpack/webpack/issues/304
          ]
        },
        resolve: {
          root: root,
          extensions: extensions,
          modulesDirectories: modulesDirectories
        }
      })).
      pipe(gulp.dest('test-build'));
  })

}

function runAllTests(gulp, options) {
  var optionsForTests = _.merge({
    ignore: ['**/node_modules/**']
  }, options);

  return new Promise(function (resolve, reject) {
    var karmaConfig = path.join(path.resolve(__dirname, '..'), 'karma.conf.js');

    // shim Prototype.function.bind in PhantomJS 1.x
    var testFiles = [
      'node_modules/es5-shim/es5-shim.min.js',
      'node_modules/es5-shim/es5-sham.min.js',
      'test-build/bundle.js'];

    gulp.src(testFiles).
      pipe(plumber({
        errorHandler: function (error) {
          console.log(error);
          this.emit('end');
        }
      })).
      pipe(karma({
        configFile: karmaConfig,
        action: 'run'
      })).
      on('end', function () { resolve(); });
  });
}

Gulp 文件:

var gulp = require('gulp');
var auctionataBuild = require('auctionata-build');
var path = require('path');

auctionataBuild.tasks.karma(gulp, {
  cwd: path.resolve(__dirname)
});

运行 来自终端:

 gulp karma