Ответ 1
Одним из возможных решений может быть требование всегда с расширением файла:
var Checkout = require('./components/Checkout.jsx')
TL;DR: я могу require
все, чтобы приложение выполнялось, но если я require
модулей из теста (который находится в приложении - см. структуру dir ниже) файл, целая цепочка зависимостей прерывается.
У меня возникли трудности с require
-интервалком компонентов из моего каталога 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, у меня есть настройка для использования 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')
поэтому, когда я требую Checkout
из index.jsx, он без проблем справляется с требованием кнопки.
Однако, из app/test/test.js, я делаю
var Checkout = require('../components/Checkout')
и веб-пакет не может найти компонент Checkout. Когда я просматриваю тесты на сервере webpack dev, он не показывает, что искалось расширение .jsx. Он искал
app/components/Checkout
app/components/Checkout.webpack.js
app/components/Checkout.web.js
app/components/Checkout.js
app/components/Checkout.json
Поэтому я попытался использовать jsx-loader
inline, как этот
var Checkout = require(jsx-loader!'../components/Checkout')
из тестового каталога, и webpack теперь может найти файл, но он выдает сообщение об ошибке, говоря, что он не может разрешить кнопку Checkout requires
. Другими словами, когда я использую require
изнутри папки app/test
, вся цепочка зависимостей выбрасывается из синхронизации.
Как я могу изменить свой файл webpack.config.js, чтобы иметь возможность требовать файлы приложений в моих тестах с этой структурой каталогов или, в более общем плане, как настроить веб-пакет для запроса файла приложения в тесте?
Update
Структура проекта
/app
/test/test.js
/index.jsx
/components/checkout.jsx (and button.jsx)
/dist
/node_modules
package.json
webpack.config.js
полная версия веб-пакета
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" в качестве корневого каталога. Но это не ясно, пока вы не разделите свой код. Можете ли вы дать ссылку на репозиторий GitHub или что-то еще?
Я вижу, что вы используете параметр гармонии, могу ли я предположить, что вы используете, es6?
Если бы у меня была эта проблема раньше, проблема для меня заключалась в том, что файлы, которые были добавлены, как es6 без преобразования, в es5 с помощью jsx-loader/babel-loader.
поэтому мне нужно было добавить:
preLoaders: [{
test: [/\.jsx$/, /\.js$/],
include: // modules here
loaders: ['babel-loader?optional[]=runtime']
}]
но тогда это не объяснит, почему это только терпит неудачу для ваших тестов. возможно, вы можете подробно остановиться на том, что запускается, когда вы запускаете свои тесты но пока я все еще в предположении, что вы используете es6,
если вышеуказанная ситуация не подходит для вас, попробуйте установить локальную версию webpack и найдите ее в локальном каталоге, а также в папке вашего приложения
(resolveLoader: { root: path.join(__dirname, "node_modules") })
надеюсь, что это поможет
изменить: ps, глядя на вашу конфигурацию, resolLoader не должен быть частью вашего решения, в другой настройке 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']
},
Я настраиваю отдельную задачу 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