在Webpack React应用程序中创建一个测试入口点。

10
tldr: 我能够使用require让应用程序运行,但如果我从测试文件(在应用程序中-请参见下面的目录结构)中require模块,则整个依赖链将会中断。
我在我的Webpack React.js应用程序中的app/test目录中有一些困难,无法像从/app文件夹中的任何其他文件那样require-ing组件。这是目录结构:
app
  /components/checkout.jsx
  /components/button.jsx
  /test/test.js 
  index.jsx  
dist
node_modules
webpack.config.js
package.json

在我的 webpack.config.js 文件中,我已经设置了使用 jsx-loader 来处理我的 React 应用程序,就像这样:

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中require Checkout时,它可以毫无问题地处理Button的require。

然而,在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所需的Button。换句话说,当我从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')

    ]
}

你是如何设置webpack配置来运行测试的?它与主配置相同还是不同?在我的设置中,我使用了两个不同的配置来运行开发构建和React测试。类似问题的解决方法是在webpack中添加 resolve: { extensions: ['', '.js', '.jsx'] } 来运行测试。 - Yevgen Safronov
@EugeneSafronov,目前我只有一个webpack配置文件在项目的顶层。我将其副本放在了更新部分,并提供了有关项目结构的更多详细信息。我考虑使用第二个配置文件进行测试,但不知道应该将其放在哪里或如何配置它。您能提供一些相关信息吗? - Leahcim
你的加载器中不是缺少了 include: __dirname 吗?同时尝试一下:/\.jsx?$/ - knowbody
@knowbody,这些建议都没有解决问题。 - Leahcim
@Leahcim,我一上我的笔记本电脑就会看看它。 - knowbody
4个回答

3

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

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

这让我能够特别要求该组件,但在运行测试时,它会说 JSX 标记(即 <)是“意外的”。应用程序仍然正常工作,只是测试存在问题。正如我在 OP 中所述,“当我从应用程序/测试文件夹中使用 require 时,整个依赖链就会失去同步。”,因此我认为问题与我的 webpack.config.js 文件有关,其中相关部分在 OP 中显示。 - Leahcim

3

我猜这可能是因为将"test"设置为根目录。但在您分享代码之前不清楚。您能给我一个GitHub存储库的链接或其他东西吗?


测试入口已被移除(请参见 OP 的更新)。该项目不在 Github 上。 - Leahcim
我在谈论这个:root: ['/app', '/test'],它仍然存在于你的webpack配置中。 - gyzerok

3

我看到你正在使用harmony参数,我可以猜测你在使用ES6吗?

如果是这样,我之前也遇到过这个问题,它的原因是文件以ES6的形式添加,但没有被JSX-loader / Babel-loader转换成ES5。

所以我需要添加:

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

但是这并不能解释为什么只有你的测试失败了。也许您可以详细说明运行测试时发生了什么。

但目前我仍然认为你在使用es6。

如果以上情况对您不适用,请尝试安装本地版本的webpack,并在本地目录以及应用程序文件夹中查找它。

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

希望这能有所帮助。
编辑:PS,根据您的配置,resolveLoader不应该作为解析器的一部分。在我使用的另一个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']
},

我正在使用JSX,但不是ES6。在您的答案末尾,将“modulesDirectories”放置在“resolve”和“resolveLoader”中。它应该两者都有吗? - Leahcim

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接