Skip to content

An example of this working with Babel/ES6, Webpack, HMR, Typescript would be super helpful:) #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
hydrotik opened this issue Nov 6, 2015 · 24 comments
Labels

Comments

@hydrotik
Copy link

hydrotik commented Nov 6, 2015

I've been combing through the repo, the issues, and your blog posts and I seem to be missing something here so forgive the rudimentary "issue" == support. Because there are so many moving parts to this tooling setup, it's harder for people to get up to speed with this and I could use a bit of help which hopefully might help the next person:) Currently in my setup I have the following:

Webpack config taking out react-hot doesn't seem to help.

{
            test: /\.ts(x?)$/,
            loader: 'react-hot!babel-loader!ts-loader',
            exclude: /node_modules/
}

tsconfig.json

{
    "compilerOptions": {
        "target" : "es6",
        "jsx" : "react"
    },
    "files": [
        "typings/react/react.d.ts"
    ]
}

app.jsx (my facade - Note it is in regular es6 jsx)

import 'babel-polyfill';
import 'normalize.css/normalize.css';

//import '../node_modules/slick-carousel/slick/slick.css';
//import '../node_modules/slick-carousel/slick/slick-theme.css';

import './scss/app.scss';

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

ReactDOM.render(
  <App />,
  document.getElementById('app')
);

My App component in .tsx in ./components/App/App

import * as React from 'react';

const Component = React.Component;

const displayName = 'App';

interface Props {
    foo: string;
}

class App extends Component<Props, {}> {

    componentDidMount() {
    }

    componentWillUnmount() {
    }

    render() {

        return (
            <div className = "app">
                HELLO WORLD
            </div>
        );
    }
}

And I am still getting the error:

[1] ERROR in ./src/global/client/components/App/App.tsx
[1] Module parse failed: /myprojectname/node_modules/react-hot-loader/index.js!/myprojectname/node_modules/babel-loader/index.js!/myprojectname/node_modules/ts-loader/index.js!/myprojectname/src/global/client/components/App/App.tsx Line 3: Unexpected token
[1] You may need an appropriate loader to handle this file type.
[1] | /* REACT HOT LOADER */ if (module.hot) { (function () { var ReactHotAPI = require("/myprojectname/node_modules/react-hot-loader/node_modules/react-hot-api/modules/index.js"), RootInstanceProvider = require("/myprojectname/node_modules/react-hot-loader/RootInstanceProvider.js"), ReactMount = require("react/lib/ReactMount"), React = require("react"); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } try { (function () {
[1] | 
[1] | import * as React from 'react';
[1] | const Component = React.Component;
[1] | const displayName = 'App';
[1]  @ ./src/global/client/app.jsx 19:11-42
[1] webpack: bundle is now VALID.
@hydrotik
Copy link
Author

hydrotik commented Nov 6, 2015

And SASS too would be great;)

@johnnyreilly
Copy link
Member

@jbrantly
Copy link
Member

jbrantly commented Nov 7, 2015

so forgive the rudimentary "issue" == support

Not a problem!

I would love to get an example going like you mentioned (it's the long term goal of my blog post series). However, I honestly don't see having the time to get all of that done anytime soon. I can give you a few tips though.

Regarding the error you're seeing, it looks like Babel isn't transforming your source for some reason. I honestly don't know why that would be. Is it possible Babel is configured elsewhere to not do certain transformations?

Regarding an example with hot reloading, https://github.com/keokilee/react-typescript-boilerplate recently made some rounds on twitter. It's using the new pattern for hot reloading (using a Babel transform instead of react-hot-loader).

@hydrotik
Copy link
Author

hydrotik commented Nov 7, 2015

Thank you both! I will take a look at these and report my findings :) 👍

@hydrotik
Copy link
Author

hydrotik commented Nov 8, 2015

There is a lot of great information in both of the examples you shared. I made some progress incorporating a couple practices such as referencing the tsd and modifications to my tsconfig. At this point I am getting the dreaded invalid token error using this code, although I seem to be getting a new error that I am unsure of.

./app.tsx

/// <reference path="../../../typings/tsd.d.ts" />

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

ReactDOM.render(<App />, document.getElementById('app'));

./components/App/App.tsx

/// <reference path="../../../../../typings/tsd.d.ts" />

import * as React from 'react';

export default class App extends React.Component<{}, {}> {
    public render(): React.ReactElement<{}> {
        return (<div>
            HELLO WORLD
        </div>
        );
    }
}

Which is throwing:

[1] ERROR in ./src/global/client/app.tsx
[1] (7,18): error TS2604: JSX element type 'App' does not have any construct or call signatures.
[1] 
[1] ERROR in ./src/global/client/app.tsx
[1] Module build failed: SyntaxError: /myprojectname/node_modules/ts-loader/index.js!/myprojectname/src/global/client/app.tsx: Unexpected token (4:16)
[1]   2 | import * as ReactDOM from 'react-dom';
[1]   3 | import * as App from './components/app/App';
[1] > 4 | ReactDOM.render(<App />, document.getElementById('app'));

Also something to note is that when I change my tsconfig.json from "jsx" : "preserve" to "jsx" : "react" I get the appropriate loader error. Seems preserve is the right way as I want Babel to handle the jsx transform?

@johnnyreilly
Copy link
Member

I notice you're using React-DOM which implies that you're using React 0.14.x.

To my knowledge the latest typings for React on Definitely Typed are 13.3. I think @jbrantly is working on the 0.14.x Typings at present. This might be throwing you for a loop in the meantime..

@hydrotik
Copy link
Author

hydrotik commented Nov 9, 2015

Thanks for that catch! I will keep my eye out for DefinitelyTyped/DefinitelyTyped#6205

@basarat
Copy link
Member

basarat commented Nov 9, 2015

You have

export default class App 

And you import it as (which is wrong):

import * as App from './components/app/App';

default imports should be done as import App from './components/app/App'. Hence the error JSX element type 'App' does not have any construct or call signatures .

Note : your IDE should already be highlighting this as an error. If not give atom-typescript a go :P (shameless plug 🌹)

PS: Personally I highly dislike default as I've seen it break too many times in refactoring. I'd rather export var foo / import {foo} from ...

@hydrotik
Copy link
Author

hydrotik commented Nov 9, 2015

Thank you @basarat, yes this solved my problem. However if I try to do:

export class App extends React.Component<{}, {}> {
    public render(): React.ReactElement<{}> {
        return (<div>
            HELLO WORLD
        </div>
        );
    }
}

I still get the error with import * as App from './components/app/App';, which should be valid as far as I know. I also tried without the export declaration and no change. Might have something to do with my current type definition pointing to .13 that @johnnyreilly mentioned above. I have Atom downloaded and I will give it a try. Still have a lot of my stuff setup in Sublime which works here and there which is most likely a fault of my own. If you recommend any packages for Sublime, feel free to share:) In the meantime I will continue with default with caution until some of the other issues get resolved with some updates and will jump back to cleaning that up.

@basarat
Copy link
Member

basarat commented Nov 9, 2015

Might have something to do with my current type definition pointing to .13 that @johnnyreilly mentioned above

Unlikely. If you have react-dom definitions (already available on DT) it would work just fine.

I still get the error with import * as App from './components/app/App'

Error message please. 🌹

@hydrotik
Copy link
Author

hydrotik commented Nov 9, 2015

My mistake:) It is working without default.
./app.tsx

/// <reference path="../../../typings/tsd.d.ts" />

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { App } from './components/app/App';

ReactDOM.render(<App />, document.getElementById('app'));

./components/App/App/App.tsx

/// <reference path="../../../../../typings/tsd.d.ts" />

import * as React from 'react';

export class App extends React.Component<{}, {}> {
    public render(): React.ReactElement<{}> {
        return (<div>
            HELLO WORLD
        </div>
        );
    }
}

Now all I am getting is the jsx token issue.

[1] ERROR in ./src/global/client/app.tsx
[1] Module build failed: SyntaxError: /myprojectname/node_modules/ts-loader/index.js!/myprojectname/src/global/client/app.tsx: Unexpected token (4:16)
[1]   2 | import * as ReactDOM from 'react-dom';
[1]   3 | import { App } from './components/app/App';
[1] > 4 | ReactDOM.render(<App />, document.getElementById('app'));
[1]     |                 ^
[1]   5 | 

@hydrotik
Copy link
Author

hydrotik commented Nov 9, 2015

Figured I would note that I do have working (with the exception of HMR), the ability to compile successfully by bypassing the babel-loader. By changing the following:
tsconfig.json

{
  "compilerOptions": {
    "target": "ES5",
    "jsx": "react"
  },
  "exclude": ["node_modules", "config", "dev_server.js"]
}

webpack config

        {
            test: /\.ts(x?)$/,
            loader: 'react-hot!ts-loader',
            exclude: /node_modules/
        }

I'm now curious why the HMR isn't working as it would seem to be more efficient to bypass the babel transform step? From what I am seeing so far, HMR isn't supported yet.

#40

Also including the babel loader and going to es5 with jsx as react works error free but again doesn't enable HMR functionality.

@johnnyreilly
Copy link
Member

PS: Personally I highly dislike default as I've seen it break too many times in refactoring. I'd rather export var foo / import {foo} from ...

Destructuring is, in my opinon, the most addictive part of ES6. Looked weird when I first saw it, now I can't stop using it! ❤️

@hydrotik
Copy link
Author

Forgive my deliberate repetition. I am trying to record this info so I make sure I'm not repeating my work:)

So here's where I am at currently:

  1. Using React .14, Babel 6, and Typescript 1.6 with ts-loader 0.6.0 and webpack config with react-hot!babel-loader!ts-loader and tsconfig with "target": "ES6", "jsx": "preserve" and "transform-react-jsx" in .babelrc gives me the Unexpected Token error.
  2. Using the same above with webpack react-hot!ts-loader and tsconfig with "target": "ES5", "jsx": "react" and "transform-react-jsx" in .babelrc gives me no error, but I don't have HMR
  3. Using the above with webpack config react-hot!babel-loader!ts-loader`` and tsconfig with"target": "ES5", "jsx": "react"and"transform-react-jsx"``` in .babelrc also gives me no error, but I don't have HMR

To clarify 1 and 2 above, if I edit my ./app.tsx file (which is my entry file in webpack config), I get a reload, but if I edit ./components/App/App.tsx then I don't. Also editing my sass file in import './_App.scss'; does nothing. My app.tsx file is reloading because I am using 'webpack/hot/dev-server' but when I use 'webpack/hot/only-dev-server' I get the expected:

[Warning] [HMR] The following modules couldn't be hot updated: (They would need a full reload!)
[Warning] [HMR]  - 66

Which points to:

[1]    [66] ./src/global/client/app.tsx 1.57 kB {0} [built]

So I'm left with the existing questions/tasks.

  1. Do I even pursue the need to use the Babel transform between ts-loader and what hopefully will be a working react-hot?
  2. I am going to explore this Typescript support gaearon/react-hot-loader#209 and see if this yields any results.
  3. Is it worth incorporating any of the hmr logic here http://webpack.github.io/docs/hot-module-replacement.html that is included in https://github.com/keokilee/react-typescript-boilerplate/blob/master/app/index.tsx
  4. I will continue to watch @keokilee https://github.com/keokilee/react-typescript-boilerplate project as there are issues Upgrade to Babel 6 keokilee/react-typescript-boilerplate#23 and React 0.14 Definitions keokilee/react-typescript-boilerplate#10 (which don't affect the remaining problem of HMR, but are worth tracking)
  5. In the https://github.com/keokilee/react-typescript-boilerplate project, the Upgrade to Babel 6 keokilee/react-typescript-boilerplate#23 issue mentions Babel 6 gaearon/babel-plugin-react-transform#46 I'm wondering if when issue Babel 6 gaearon/babel-plugin-react-transform#46 is addressed, is it better than using "transform-react-jsx" in my .babelrc file and switch to https://github.com/gaearon/babel-plugin-react-transform. Something to note which could change with this issue is the format of https://github.com/gaearon/react-transform-boilerplate/blob/master/.babelrc

@jbrantly
Copy link
Member

  1. Using React .14, Babel 6, and Typescript 1.6 with ts-loader 0.6.0 and webpack config with react-hot!babel-loader!ts-loader and tsconfig with "target": "ES6", "jsx": "preserve" and "transform-react-jsx" in .babelrc gives me the Unexpected Token error.

I have had trouble in the past with getting babel-loader to pick up on my .babelrc file. I don't remember the specifics but I did wind up just passing it to the loader manually in the webpack config by using the babel option (undocumented). Might be worth trying.

// webpack.config.js
module.exports = {
  ...
  babel: {
    ...
  }
}
  1. Using the same above with webpack react-hot!ts-loader and tsconfig with "target": "ES5", "jsx": "react" and "transform-react-jsx" in .babelrc gives me no error, but I don't have HMR
  2. Using the above with webpack config react-hot!babel-loader!ts-loader`and tsconfig with"target": "ES5", "jsx": "react"and"transform-react-jsx"`` in .babelrc also gives me no error, but I don't have HMR

Not sure, I'm not really familiar with react-hot-loader, only with the new stuff that uses Babel transformations.

  1. In the https://github.com/keokilee/react-typescript-boilerplate project, the Upgrade to Babel 6 keokilee/react-typescript-boilerplate#23 issue mentions Babel 6 gaearon/babel-plugin-react-transform#46 I'm wondering if when issue Babel 6 gaearon/babel-plugin-react-transform#46 is addressed, is it better than using "transform-react-jsx" in my .babelrc file and switch to https://github.com/gaearon/babel-plugin-react-transform. Something to note which could change with this issue is the format of https://github.com/gaearon/react-transform-boilerplate/blob/master/.babelrc

From my own experience, this would be the way to go. Just use Babel 5 for now, and once react-transform is updated then switch.

@johnnyreilly
Copy link
Member

Just a minor point: there's a problem with sourcemaps in Babel 6. As @jbrantly says stick with 5 for now. It can be tracked here:

babel/babel#2864

@keokilee
Copy link

Having done Node Knockout this weekend, there were more than a few instances where HMR would stop working for whatever reason. I'll have to set aside some time to investigate further.

@hydrotik
Copy link
Author

So... I can't go back down to Babel 5 because I'm also using Hapi with hapi-react-views that has a version that requires Babel 6 if you are using React .14 👊

jedireza/hapi-react-views#31

So I wait patiently as I continue to:
http://i.imgur.com/o9wN0Rs.gif

@jbrantly
Copy link
Member

@keokilee Definitely interested in any cases like that. I'm only aware of one issue related to hot reloading which is documented in #52. For the most part hot reloading issues have less to do with the TypeScript loader and more to do with other aspects of the process. There is a lot that has to go right to get hot reloading working, and a lot depends on what you're trying to hot reload (for instance, a React component vs a helper library) and even what you're changing within that thing (for instance, React's render method vs an event handler).

@hydrotik
Copy link
Author

A little off topic, but anyone compared with awesome-typescript-loader?

Also if anyone can suggest a place to understand a good process for pulling in external libs for React (such and react-slick) into Typescript projects, i'd be eternally grateful:) @jbrantly sorry for spamming you :/

@Keats
Copy link

Keats commented Dec 1, 2015

Got an example working there https://github.com/Keats/flow-typescript/tree/master/typescript if people want another example

@alexgorbatchev
Copy link

I have a working boilerplate that is still WIP https://github.com/alexgorbatchev/gulp-typescript-webpack-react-hotreload

@johnnyreilly
Copy link
Member

My example has now been updated to Babel 6 following the fix.

@jbrantly
Copy link
Member

FYI I've added the examples/boilerplates from this thread to https://github.com/TypeStrong/ts-loader/wiki/Tutorials-&-Examples and linked it from the README

I'm going to close this thread since I don't believe there are any open items in it (it kind of wondered a bit). If I'm mistaken please feel to open new issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants