Node + React + Babel + Webpack,意外的令牌错误

时间:2017-03-02 01:00:02

标签: javascript reactjs webpack

首先,我真的试图自己解决这个问题,我在这里找到了几个类似的问题,但没有人帮助我。

出现此错误:

ERROR in ./src/components/App.jsx
Module parse failed: D:\JS projects\habr-app\src\components\App.jsx Unexpected token (54:6)
You may need an appropriate loader to handle this file type.
|   render() {
|     return (
|       <div className='App'>
|         <h1>Hello World!</h1>
|         <div>
 @ ./src/client.js 3:0-42
 @ multi (webpack)-dev-server/client?http://0.0.0.0:8050 webpack/hot/dev-server babel-polyfill ./src/client.js

client.js文件:

import React      from 'react';
import ReactDOM   from 'react-dom';
import App        from './components/App';

ReactDOM.render ("<App />", document.getElementById('react-view'));
App.jsx中的

渲染功能如下所示:

render() {
    return (
      <div className='App'>
        <h1>Hello World!</h1>
        <div>
          <p>Введите Ваше имя:</p>
          <div><input onChange={this.handleNameChange} /></div>
          {this.renderGreetingWidget()}
        </div>
      </div>
    );
  }

webpack.config.js文件:

global.Promise         = require('bluebird');

var webpack            = require('webpack');
var path               = require('path');
var ExtractTextPlugin  = require('extract-text-webpack-plugin');
var CleanWebpackPlugin = require('clean-webpack-plugin');

var publicPath         = 'http://localhost:8050/public/assets';
var cssName            = process.env.NODE_ENV === 'production' ? 'styles-[hash].css' : 'styles.css';
var jsName             = process.env.NODE_ENV === 'production' ? 'bundle-[hash].js' : 'bundle.js';

var plugins = [
  new webpack.DefinePlugin({
    'process.env': {
      BROWSER:  JSON.stringify(true),
      NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development')
    }
  }),
  new ExtractTextPlugin(cssName)
];

if (process.env.NODE_ENV === 'production') {
  plugins.push(
    new CleanWebpackPlugin([ 'public/assets/' ], {
      root: __dirname,
      verbose: true,
      dry: false
    })
  );
  plugins.push(new webpack.optimize.DedupePlugin());
  plugins.push(new webpack.optimize.OccurenceOrderPlugin());
}

module.exports = {
  entry: ['babel-polyfill', './src/client.js'],
  resolve: {
    extensions:         ['.js', '.jsx']
  },
  plugins: [
     new ExtractTextPlugin("styles.css"),
     new webpack.LoaderOptionsPlugin({
       debug: true,
       options: {
         eslint: { configFile: '.eslintrc' }
       }
     })
  ],
  output: {
    path: `${__dirname}/public/assets/`,
    filename: jsName,
    publicPath
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        })
      }
    ],
    loaders: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!postcss-loader'})
      },
      {
        test: /\.less$/,
        loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!postcss-loader!less-loader'})
      },
      { test: /\.gif$/, loader: 'url-loader?limit=10000&mimetype=image/gif' },
      { test: /\.jpg$/, loader: 'url-loader?limit=10000&mimetype=image/jpg' },
      { test: /\.png$/, loader: 'url-loader?limit=10000&mimetype=image/png' },
      { test: /\.svg/, loader: 'url-loader?limit=26000&mimetype=image/svg+xml' },
      { test: /\.(woff|woff2|ttf|eot)/, loader: 'url-loader?limit=1' },
      { test: /\.jsx?$/, loaders: ['react-hot-loader', 'babel-loader?presets[]=react,presets[]=es2015'],
                          exclude: [/node_modules/, /public/] , query: {presets: ['es2015', 'react', 'react-hot']} },
      { test: /\.json$/, loader: 'json-loader' },
    ]
  },
  devtool: process.env.NODE_ENV !== 'production' ? 'source-map' : null,
  devServer: {
    headers: { 'Access-Control-Allow-Origin': '*' }
  }
};

我能解决这个问题的唯一方法是在渲染中放置html引号:

render() {
    return (
      `<div className='App'>
        <h1>Hello World!</h1>
        <div>
          <p>Введите Ваше имя:</p>
          <div><input onChange={this.handleNameChange} /></div>
          {this.renderGreetingWidget()}
        </div>
      </div>`
    );
  }

但之后我在浏览器和nodemon中遇到了这个错误:

Invariant Violation: App.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.

我检查并重新检查了所有依赖项,模块和我的文件。 不过,我找不到错误。有人可以帮帮我吗?

P.S。对不起我糟糕的英语。

有趣的是。当我在App.jsx中没有这些引号的情况下启动nodemon时,我的页面会加载,但没有css。之后,我在文件App.jsx中添加了引号,现在webpack-devserver构建了一切正确,并且页面在刷新后获得.css。 JS脚本仍然没有工作,但看起来几乎应该...直到我重新启动nodemon ...它开始显示相同的错误“不变违反:App.render():一个有效的React元素(或null)必须返回。您可能已经返回undefined,数组或其他一些无效对象。“

1 个答案:

答案 0 :(得分:1)

错误告诉您没有定义可以处理JSX的加载器,尽管它可能看起来像您在webpack配置中所做的那样。问题是您定义了module.rulesmodule.loaders。当webpack看到module.rules时,它会完全忽略module.loaders(尽管出于兼容性原因它仍然存在)。修复很简单,只需将所有加载器放在module.rules下。

您的.jsx?规则中也存在问题,因为query(也已弃用并替换为options)不能用于加载器数组,而是应该在数组中的每个加载器中定义。因为你把它作为字符串内联,所以根本不需要它。

要获得有效的配置,请将module部分替换为:

module: {
  rules: [
    {
      test: /\.css$/,
      loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!postcss-loader'})
    },
    {
      test: /\.less$/,
      loader: ExtractTextPlugin.extract({fallback: 'style-loader', use: 'css-loader!postcss-loader!less-loader'})
    },
    { test: /\.gif$/, loader: 'url-loader?limit=10000&mimetype=image/gif' },
    { test: /\.jpg$/, loader: 'url-loader?limit=10000&mimetype=image/jpg' },
    { test: /\.png$/, loader: 'url-loader?limit=10000&mimetype=image/png' },
    { test: /\.svg/, loader: 'url-loader?limit=26000&mimetype=image/svg+xml' },
    { test: /\.(woff|woff2|ttf|eot)/, loader: 'url-loader?limit=1' },
    { test: /\.jsx?$/, use: ['react-hot-loader', 'babel-loader?presets[]=react,presets[]=es2015'],
      exclude: [/node_modules/, /public/] },
    { test: /\.json$/, loader: 'json-loader' },
  ]
},

如果您决定使用options,这绝对更具可读性,那么您的.jsx?规则将如下所示:

{
  test: /\.jsx?$/,
  use: [
    'react-hot-loader',
    { loader: 'babel-loader', options: { presets: ['react', 'es2015'] } },
  ],
  exclude: [/node_modules/, /public/]
}

use的文档所示。