.tsx webpack compile fails: Unexpected token <
Asked Answered
S

1

7

My app compiles with .ts, .js, and .jsx files and runs. Now I try changing a .jsx file to .tsx and it breaks.

How do I fix this compile error:

ts-loader: Using [email protected] and C:\users\ruser\Desktop\Downloads\divinote\site\tsconfig.json                                                                                                                                                    67% 226/234 build modulesModuleParseError: Module parse failed: C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\ts-loader\index.js?cacheDirectory!C:\users\ruser\Desktop\Downloads\divinote\site\src\app\views\header\DiviAppBar.tsx 
Line 15: Unexpected token <
You may need an appropriate loader to handle this file type.
|     }
|     DiviAppBar.prototype.render = function () {
|         return (<AppBar />);
|     };
|     return DiviAppBar;
    at DependenciesBlock.<anonymous> (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack\lib\NormalModule.js:113:20)
    at DependenciesBlock.onModuleBuild (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:310:10)
    at nextLoader (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:275:25)
    at C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:292:15
    at context.callback (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:148:14)
    at Object.loader (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\ts-loader\index.js:431:5)
    at WEBPACK_CORE_LOADER_EXECUTION (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:155:71)
    at runSyncOrAsync (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:155:93)
    at nextLoader (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:290:3)
    at C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\webpack-core\lib\NormalModuleMixin.js:259:5
    at Storage.finished (C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:38:16)
    at C:\users\ruser\Desktop\Downloads\divinote\site\node_modules\graceful-fs\graceful-fs.js:76:16
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:404:3)                                                                                                                                                                                     69% 337/338 build moduleschild_process.js:484

when I compile this code:

"use strict";
import React = require('react');
import AppBar = require('material-ui/lib/app-bar');

class DiviAppBar extends React.Component
{
    render()
    {
        return (
            <AppBar  />
        );
    }
}

export = DiviAppBar;

with this webpack config file:

'use strict';

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var path = require('path');
var rootPath = __dirname; //site
var srcPath = path.join(rootPath, 'src'); //site/src

module.exports =
{
    bail: true,
    cache: true,
    context: rootPath,
    debug: true,
    devtool: 'inline-source-map', //'eval-cheap-module-source-map','inline-source-map'
    target: 'web',
    devServer:
    {
        contentBase: './dist',
        historyApiFallback: true
    },
    entry:
    {
        app: path.join(srcPath, 'app/main.jsx'),
        lib: ['react', 'react-router']
    },
    output:
    {
        path: path.join(rootPath, 'dist'),
        publicPath: '',
        filename: '[name].js',
        library: ['[name]', '[name]'],
        pathInfo: true
    },
    resolve:
    {
        root: srcPath,
        extensions: ['', '.js', '.jsx', '.ts', '.tsx'],
        modulesDirectories: ['node_modules', 'src', 'typings']
    },
    module:
    {
        loaders:
        [
            {test: /\.js$/, loader: 'babel-loader?cacheDirectory', exclude: /(node_modules|bower_components)/ },
            {test: /\.jsx$/, loader: 'babel-loader?cacheDirectory', exclude: /(node_modules|bower_components)/ },
            {test: /\.ts$/, loader: 'ts-loader?cacheDirectory', exclude: /(node_modules|bower_components)/ },
            {test: /\.tsx$/, loader: 'ts-loader?cacheDirectory', exclude: /(node_modules|bower_components)/ },
            {test: /\.scss$/, loaders: ['style', 'css', 'sass']},
            {test: /\.png$/, loader: 'file-loader'},
            {test: /\.jpg$/, loader: 'file-loader'},
            {test: /\.jpeg$/, loader: 'file-loader'},
            {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?mimetype=image/svg+xml'},
            {test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/font-woff"},
            {test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/font-woff"},
            {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/octet-stream"},
            {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader"},
        ]
    },
    plugins:
    [
        new CopyWebpackPlugin
        ([
            { from: 'src/images', to: 'images' }
        ]),
        new webpack.optimize.CommonsChunkPlugin('lib', 'lib.js'),
        new HtmlWebpackPlugin
        ({
            inject: true,
            template: 'src/index.html'
        }),
        new webpack.NoErrorsPlugin()
    ]
};

and this tsconfig.json file:

{
    "compilerOptions":
    {
        "jsx": "preserve",
        "noImplicitAny": true,
        "module": "commonjs",
        "removeComments": false,
        "sourceMap": true,
        "target": "es5"
    },
    "files": [],
    "exclude":
    [
        "node_modules",
        "dist"
    ]
}
Statesmanship answered 14/12, 2015 at 8:14 Comment(4)
What does happen when you change "jsx": "preserve" -> "jsx": "react"?Duncan
It seems to be better, now this line class DiviAppBar extends React.Component gives me the error TS2314: Generic type 'Component<P, S>' requires 2 type argument(s). But surely it shouldn't make a difference? preserve means .tsx will become .jsx, and then Babel will transform it to .js, like it was working before. react means ts-loader will turn .tsx straight into .js.Statesmanship
I would first try to upgrade TS to TS 1.7 (github.com/Microsoft/TypeScript/releases) to avoid a chance that it's just a bug in TS.Duncan
Done. TS 1.7.3 gives the same error. I guess I could leave it as react, but I'd really compilation to work either way, and to know why it's failing :-(Statesmanship
A
2

The first issue has to do with "jsx" config as mentioned by Martin. Set "jsx" to "react".

The second issue has to do with your code. Change it like this:

class DiviAppBar extends React.Component<Props, State> ...

Create an interface for your props and another one for your state. If you don't have any use empty objects.

class DiviAppBar extends React.Component<{}, {}> ...
Akilahakili answered 14/12, 2015 at 8:55 Comment(7)
Because "preserve" will output "jsx" files instead of "js". Are you going to pass that output to babel? If yes, use preserve and "target": "es6". if not, use "jsx": "react", "target": "es5". I couldn't see the relevant code in your question.Akilahakili
Ahh, nowhere in the tsconfig.json docs did I see those two settings have to be used in conjunction. Thanks.Statesmanship
They're not related. It's just how you want your output to be. Most browsers don't support "es6" and this is why we choose "es5". If you were planning to only work with a specific browser, say a chrome extension or a phonegap application, then you'd choose target: "es6", jsx: "react".Akilahakili
Oh, then I still don't get why "preserve" fails the compilation step while "react" succeeds. Annoying new fangled tech. I want Turbo Pascal back.Statesmanship
That's a webpack issue I think. "You may need an appropriate loader to handle this file type." You're passing jsx file as a js to another loader (not ts-loader). It's probably an internal loader. To fix this change the line test: /\.tsx$/, loader: 'ts-loader?cacheDirectory' to test: /\.tsx$/, loader: 'ts-loader?cacheDirectory!babel-loader' and it should work.Akilahakili
So think about it like this: .tsx -[ts-loader]-> .jsx -[webpack bundler]-> .js Webpack bundler expects a js file, it doesn't understand jsx. You get an error. .tsx -[ts-loader]-> .jsx -[babel-loader]-> .js -[webpack bundler]-> .js This should be ok. Lastly, with jsx: react, you get .tsx -[ts-loader]-> .js -[webpack bundler]-> .js and that's OK.Akilahakili
@LouayAlakkad, hello, any idea about this problem? #69190635Wychelm

© 2022 - 2024 — McMap. All rights reserved.