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 typescript@1.6.2 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"
    ]
}
Richard
  • 14,798
  • 21
  • 70
  • 103
  • 1
    What does happen when you change `"jsx": "preserve"` -> `"jsx": "react"`? – MartyIX Dec 14 '15 at 08:18
  • It seems to be better, now this line **class DiviAppBar extends React.Component** gives me the error **TS2314: Generic type 'Component

    ' 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.

    – Richard Dec 14 '15 at 08:26
  • I would first try to upgrade TS to TS 1.7 (https://github.com/Microsoft/TypeScript/releases) to avoid a chance that it's just a bug in TS. – MartyIX Dec 14 '15 at 08:29
  • 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 :-( – Richard Dec 14 '15 at 08:36

1 Answers1

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<{}, {}> ...
Louay Alakkad
  • 7,132
  • 2
  • 22
  • 45
  • 2
    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. – Louay Alakkad Dec 14 '15 at 15:38
  • Ahh, nowhere in the tsconfig.json docs did I see those two settings have to be used in conjunction. Thanks. – Richard Dec 14 '15 at 18:11
  • 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"`. – Louay Alakkad Dec 15 '15 at 08:17
  • 2
    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. – Richard Dec 15 '15 at 08:55
  • 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. – Louay Alakkad Dec 15 '15 at 12:02
  • 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. – Louay Alakkad Dec 15 '15 at 12:04
  • @LouayAlakkad, hello, any idea about this problem? https://stackoverflow.com/questions/69190135/unexpected-token-container-reactjs-typescript – Maq Sep 20 '21 at 19:22