ionic-team / ionic-app-scripts

App Build Scripts for Ionic Projects
http://ionicframework.com/
MIT License
608 stars 304 forks source link

ionic build does not work with typescript@next (>= 2.1) #197

Closed chriswep closed 7 years ago

chriswep commented 8 years ago

I like to use typescript 2.1 (which is right now in the @next channel) because it enables me to use async/await while still targeting ES5.

Anyway, when using ionic build, i.e. the ngc AOT compiler, the build breaks with

[14:39:02] Error: Error at /Users/chris/Sites/emmaus-app/.tmp/app/main.prod.ts:4:36
[14:39:02] Cannot find module './app.module.ngfactory'.
[14:39:02] ngc failed
[14:39:02] ionic-app-script task: "build"
[14:39:02] Error: Error

Downgrading to typescript 2.0.3 solves the problem.

bytenik commented 8 years ago

Just tried installing typescript@next and it still errors on async when targeting ES5. How did you get it to work?

bytenik commented 8 years ago

Nevermind, I'm a moron.

rob3c commented 8 years ago

@metz FWIW I can successfully use async/await while targeting ES5 with ionic dev builds (using the hack below), but I haven't figured out a fix for prod builds yet.

This new ionic-app-scripts build system does two kinds of builds, dev and prod. Both systems use a project's tsconfig.json file, but the version of typescript that actually gets used for the build is inconsistent between them. (I should probably create a new issue for that...)

prod does AOT builds that ultimately invoke angular 2's tsc-wrapped module, and the angular 2 AOT compiler will respect a project's locally-installed typescript version. When I try doing a prod build via npm run build with a locally-installed typescript@2.1.0-dev.20161019, for example, I get this error:

 Error: Metadata emit requires the sourceFiles are passed to WriteFileCallback. Update to
 TypeScript ^1.9.0-dev
 ngc failed
 ionic-app-script task: "build"
 Error: Error

That Metadata emit requires... error is thrown in the @angular/tsc-wrapped/src/compiler_host.js file. It's not clear to me if it's strictly an angular 2 issue, or if the sourceFiles arg in their writeFile overload is empty because the ionic build system isn't providing what it needs correctly when using TS 2.1.0-dev.*.

Unlike prod builds, dev builds use a pinned typescript that's currently at 2.0.3, because the app-scripts module has typescript listed as a dependency instead of a peerDependency. That means, when doing dev builds, app-scripts ignores whatever version of typescript you have installed in your project and uses the one in @ionic/app-scripts/node_modules/typescript instead. That one happens to be 2.0.3 in my install, because their package.json declares the dependency as ^2.0.3 (which wouldn't pick up the 2.1.0-dev builds anyway even if it was listed like that as a peerDependency instead - I think it would need to be ^2.0.3 || ^2.1.0-dev). It's confusing, because the app-scripts build does respect the tsconfig.json file in your project. This seems like a bug!

As a workaround to at least enable async/await in non-AOT dev builds while they sort this stuff out, I was able to force app-scripts to respect the newer typescript 2.1.0-dev version installed in my project's node_modules folder by opening a terminal in @ionic/app-scripts and running npm uninstall --save typescript to get rid of the 2.0.3 version in their nested node_modules folder. Then, since node won't find it locally, it bubbles up to the node_modules folder in my project and use that one instead.

I also changed the build script in package.json to: "build": "ionic-app-scripts build --dev" to force dev builds even when using ionic run android and such that would otherwise use prod builds.

So assuming angular support for typescript 2.1.0 arrives sometime soon for AOT builds, this enables coding using the convenience of async/await in the meantime. On-device debugging is much faster with non-AOT builds anyway, so this is what I was doing already.

chriswep commented 8 years ago

thanks @rob3c for the detailed explanations, that cleared things up a bit.

danbucholtz commented 8 years ago

@metzc, @rob3c,

For now, don't do this 😆 . We want to support this, but we can't yet. We are limited by Angular AoT. There are also known issues with Typescript transpiling ES2017 to ES5 and uglify-js, etc.

We will add this support as soon as we can but for now it's not something we can offer support for now. Hopefully soon, as I am a huge async/await fanboy.

Thanks, Dan

wwoods commented 8 years ago

I'd suggest the team not close this issue... Perhaps tag it as angular-dependent or something, but this is still an active issue that is helpful for users to know about. It shouldn't be closed.

bytenik commented 8 years ago

With the team's transition to Webpack, I've had great success with hooking babel-loader into the Webpack config after their custom loader, and then telling TS to generate ES2015. It works perfectly. Its not ideal, but I'll take it.

hermitdemschoenenleben commented 8 years ago

@bytenik : Could you upload your configuration files? This would be very helpful! I tried something similar but did not succeed :(

danbucholtz commented 8 years ago

All,

I don't recommend going off and starting to customize the webpack config yet. Consider that "ejecting" like create-react-app. We can't support custom configs, especially when we're very early in the process with Webpack and app-scripts in general.

Thanks, Dan

bytenik commented 8 years ago

The following is what I used:

let config = require('@ionic/app-scripts/config/webpack.config.js');
const path = require('path');

console.log("Using alternate Webpack script");

config.devtool = 'source-map';

let loaderEntry = config.module.loaders[0];
let presetPath = path.join(__dirname, '../node_modules/babel-preset-es2015').split('\\').join('/');
loaderEntry.loaders = [ loaderEntry.loader, `babel-loader?{"cacheDirectory": true, "babelrc": false, "presets": [ ["${presetPath}", { "modules": false }] ]}` ];
delete loaderEntry.loader; 

module.exports = config;
bytenik commented 8 years ago

@danbucholtz I know its not recommended, but I don't really have a choice. Without AOT compilation, Ionic2 is unbearably slow on devices for my app -- too slow to deploy. And I already have a mostly built app from the Ionic2 betas, which uses async/await because I had added Babel into the gulp build. At this point, I don't really have an option but to tweak the current rc1 build process.

danbucholtz commented 8 years ago

@bytenik,

Sounds good. I understand people are going to need to customize. I totally, 110% get it. My fear is that since we're iterating very quickly right now there will be breaking changes, etc. We'll provide some hooks to make it easy to inject data, etc. For transpiling, adding a loader to Webpack is probably going to be the fastest way to do it.

Thanks, Dan

wwoods commented 8 years ago

@danbucholtz Once again, can we please leave this issue open? As it is, in fact, an open issue. Clearly there's a need / want for this functionality, and it is a bug when dealing with Ionic v2. This shouldn't be closed.

rob3c commented 8 years ago

@danbucholtz Do you have any specific angular, typescript and/or uglifyjs issues you can link to that are holding this up so that we can track them? Are there any other blocking problems with dependencies that don't have corresponding issues yet and still need to be created?

Kobzol commented 8 years ago

@bytenik Do you have a sample repo for this babel transpiling usage? I can't get it to work with the script that you posted.

bytenik commented 8 years ago

It works out of the box on 0.0.37. The newer app scripts versions appear to have changed everything.

chriswep commented 8 years ago

@Kobzol it also didn't work for me. here is my relevant part of the webpack.config:

config.module.loaders.push(
    {
        test: /\.js$/,
        loader: 'babel',
        exclude: path.resolve(__dirname, 'node_modules/'),
        query: {
            presets: [
                ['es2015', {
                    "modules": false
                }],
                'stage-0'
            ]
        }
    }
);

Please note that for async/await to work i also have to import the babel-generator-runtime within my app code.

danbucholtz commented 8 years ago

We are working on bundling our dependencies for app-scripts to speed up install time. Once that's done, I'll address this. I think we can get away with a peerDependency of * for TypeScript and @angular/compiler-cli. This should take care of the issues and you can use the async/await with ES5 target.

Thanks, Dan

Kobzol commented 8 years ago

@metzc Thank you, with that config I finally managed it to work x)

jamespacileo commented 8 years ago

@Kobzol @metzc could you kindly elaborate on how you got Ionic to work with TS 2.1?

Kobzol commented 8 years ago

@jamespacileo I didn't use Typescript 2.1, I just used the webpack config script provided by @metzc to transcript ES6 to ES5 with Babel. I created a script with the config that @metzc posted and added this to my package.json: "config": { "ionic_webpack": "<path_to_the_script>" } Make sure that the exclude path in the config file does point to your node_modules folder or it won't probably work and it will give strange errors since it will try to transpile your libraries. For the example script given by @metzc, the config file should be stored in the project root, where package.json is.

Then I installed

"babel-core": "^6.18.0",
"babel-loader": "^6.2.7",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-external-helpers": "^6.8.0",
"babel-plugin-external-helpers-2": "^6.3.13",
"babel-plugin-native-async-for-typescript": "^1.0.3",
"babel-plugin-syntax-async-generators": "^6.13.0",
"babel-plugin-transform-async-to-generator": "^6.16.0",
"babel-plugin-transform-regenerator": "^6.16.1",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-es2015-loose": "^8.0.0",
"babel-preset-es2015-rollup": "^1.2.0",
"babel-preset-stage-0": "^6.16.0",

I'm pretty sure that not even half of those packages are required, but it was a trial-and-error until it worked, so I'm posting all of them. Then I had to add the regenerator runtime to my code, but Ionic doesn't support multiple webpack entries at this moment and I had no luck with importing it in code, so I simply copied the runtime.js file from node_modules/regenerator-runtime to the src dir and included it in the head of index.html.

The only other thing necessary was to either turn off uglifyjs or use a newer version that handles ES6 (as stated in #239). After that async/await started to work on my mobile device :-)

chriswep commented 8 years ago

to give some context: typescript 2.1 right now is not working with Angular 2 AOT, thats why we can't use it (for production builds). If it would work, we could just use async/await out of the box because 2.1 can transpile it to ES5.

The workaround is to set the target of typescript to ES6 and transpile this to ES5 with webpack (which is able to transpile async/await for ES5).

On a side note: I was able to just do import 'babel-regenerator-runtime'; in my app code.

jamespacileo commented 7 years ago

@Kobzol @metzc thanks a ton! Worked like a charm! I appreciate the time and hard work it took to find a workaround and sharing the steps in such details. I'm so happy I can finally use async/await! Thanks 👍

Kobzol commented 7 years ago

If you're using app-scripts version 0.0.46 or newer, change the loader: 'babel' line to loader: 'babel-loader'.

iursevla commented 7 years ago

Any news on when this will run flawlessly? I only changed a thing on tsconfig.json, "target":"es5" to "target":"es2015" and async/await works on my android phone but not on emulator.

chriswep commented 7 years ago

@iursevla with only your change you end up with ES6 code in your build. though this works on some browsers and devices (say: iOS10 partly, newest chrome browser) you can't rely on it just now. maybe in 2 years or something but right now you definitely need to transpile to ES5 for production.

iursevla commented 7 years ago

@metzc thanks for your reply. What's the solution with the least changes i can do to make async/await work across all devices and emulators?

danbucholtz commented 7 years ago

Just as an FYI, Typescript 2.1 doesn't work with our build process yet but we landed a PR to make it so. They changed an existing public API. We have made the changes necessary with peerDependencies already.

Thanks, Dan

bytenik commented 7 years ago

A pull request to their code, or to Ionic?

danbucholtz commented 7 years ago

To Typescript.

https://github.com/Microsoft/TypeScript/pull/12445

Thanks, Dan

bytenik commented 7 years ago

It looks like it was merged several days ago. Does that mean that typescript@next works with the latest app-scripts?

danbucholtz commented 7 years ago

@bytenik,

Not the latest published, no, but the latest nightly (which is probably buggy) may work. I'm not sure. I haven't tested it, but the changes to the package.json involving peerDependencies are in place. I am a huge async/await fan so we'll make sure this works well soon. But there are bigger fish to fry first and we're a small team.

Thanks, Dan

bytenik commented 7 years ago

FWIW, I gave it a try anyway. No patience here. 😀 There still seems to be an issue between the @angular/compiler(-cli?) and TypeScript:

TypeError: Cannot read property 'text' of undefined
    at NodeObject.getText (C:\Users\bytenik\AppData\Roaming\npm\node_modules\typescript\lib\typescript.js:78064:30)
    at Evaluator.evaluateNode (C:\Users\bytenik\AppData\Roaming\npm\node_modules\@angular\compiler-cli\node_modules\@angular\tsc-wrapped\src\evaluator.js:495:66)
    at _loop_1 (C:\Users\bytenik\AppData\Roaming\npm\node_modules\@angular\compiler-cli\node_modules\@angular\tsc-wrapped\src\collector.js:306:54)
    at C:\Users\bytenik\AppData\Roaming\npm\node_modules\@angular\compiler-cli\node_modules\@angular\tsc-wrapped\src\collector.js:365:25
    at visitEachNode (C:\Users\bytenik\AppData\Roaming\npm\node_modules\typescript\lib\typescript.js:13907:30)
    at Object.forEachChild (C:\Users\bytenik\AppData\Roaming\npm\node_modules\typescript\lib\typescript.js:14078:24)
    at MetadataCollector.getMetadata (C:\Users\bytenik\AppData\Roaming\npm\node_modules\@angular\compiler-cli\node_modules\@angular\tsc-wrapped\src\collector.js:204:12)
    at MetadataWriterHost.writeMetadata (C:\Users\bytenik\AppData\Roaming\npm\node_modules\@angular\compiler-cli\node_modules\@angular\tsc-wrapped\src\compiler_host.js:111:51)
    at MetadataWriterHost.writeFile (C:\Users\bytenik\AppData\Roaming\npm\node_modules\@angular\compiler-cli\node_modules\@angular\tsc-wrapped\src\compiler_host.js:103:19)
    at Object.writeFile (C:\Users\bytenik\AppData\Roaming\npm\node_modules\typescript\lib\typescript.js:62519:132)
Compilation failed
jamespacileo commented 7 years ago

If there's still an issue between compiler-cli and Typescript 2.1, could someone (who knows what the problem is) kindly raise an issue on the Angular github? 😄

They've closed a few issues already stating that AOT is compatible with 1.8+ (2.1 included) and that there is no issue.

bytenik commented 7 years ago

I'm not exactly sure how to reproduce this enough to submit a ticket. I know it fails on my codebase, but I don't know that it will fail on another. @jamespacileo are you able to try this out with your code and see if it fails?

jamespacileo commented 7 years ago

@bytenik ok, I'll give it a shot this evening. Hopefully I reproduce the same error, or even better... get a successful compilation. :)

bytenik commented 7 years ago

@jamespacileo Any luck?

chriswep commented 7 years ago

for me there is still the same problem / output that i posted initially on this issue. i tried with the official typescript 2.1 release as well as nightly. i then even updated ionic-angular as well as app-scripts to nightly (and angular accordingly). no success.

is there any working example with typescript >= 2.1 and angular when using the ngc compiler (and at best ionic2)? Then i could work from there. However it seems to me that this is independent from my setup.

danbucholtz commented 7 years ago

@metzc,

I haven't tried it yet. We are holding off on updating to TS 2.1 until after 2.0.0 final.

Thanks, Dan

bytenik commented 7 years ago

I can't tell you how disappointed I am that Ionic2 will be released on an already-obsolete TypeScript version. 😭

chriswep commented 7 years ago

@danbucholtz i wouldn't complain, since you are doing a great job here. apart from that i am very much looking forward to a coming Ionic2 support of TS 2.1, seeing that it is released now. I am using its new features regularly in other projects and find them to greatly improve the platform as a development environment.

danbucholtz commented 7 years ago

@bytenik, Not our fault. Angular doesn't support Typescript 2.1. There are many open issues about it. We tried to upgrade a few weeks back, and tried again today. No dice in Angular 2.3. I don't have the issue handy but if you search TypeScript 2.1 in Angular repo you'll see a slew of issues.

Thanks, Dan

WhatsThatItsPat commented 7 years ago

TypeScript 2.1 (2.2?) support will come to Angular when they bump to 4.0.

Details in Igor's recent talk here.


And more info here.

jamespacileo commented 7 years ago

Angular 4 is scheduled for march. Hopefully that means we'll get a beta/alpha/RC way before then.

TS 2.1 is very important to me, so I'll be keeping a close eye on the Angular github. On Wed, 14 Dec 2016 at 23:14, Patrick McDonald notifications@github.com wrote:

TypeScript 2.1 (2.2?) support will come to Angular when they bump to 4.0.

Details in Igor's recent talk here https://youtu.be/aJIMoLgqU_o?t=843.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/driftyco/ionic-app-scripts/issues/197#issuecomment-267186925, or mute the thread https://github.com/notifications/unsubscribe-auth/AAlKZO95E-QAM2GlXJ4Zsgb9a_6uwBVMks5rIHhXgaJpZM4KbAcH .

danbucholtz commented 7 years ago

@jamespacileo, I'm personally as anxious for it as you are. We'll get it in there as soon as we can. Everything on our end is ready to go.

Thanks, Dan

Flavien commented 7 years ago

I don't know what I am doing wrong, but for me Typescript 2.1 works just fine with Ionic.

wmaurer commented 7 years ago

@Flavien including building and deploying to a device? I've found that using typescript 2.1 and running ionic serve is fine, but the problems only come about when running ionic run android - that's when the ng compiler kicks in, and starts causing problems. I even created a brand new blank Ionic app, only upgraded typescript to 2.1, and that failed to run on the device.

Flavien commented 7 years ago

Ok, I've only try with dev builds (Ripple emulator and Android emulator), haven't tried on an actual device.

chriswep commented 7 years ago

@danbucholtz as you guys probably now angular 4 is published as beta on npm now. just gave it a shot if it would work but i didn't come far due to changes in angular that ionic-app-scripts is not compatible with. Just for your reference: angular moved ReflectorHost from compiler-cli to language-services. Thats at least one thing that would need to be fixed.

Wonder if you would try to switch to the angular 4 betas before March 2017? In nightly / separate branch? I would appreciate.

danbucholtz commented 7 years ago

@metzc,

We will certainly be integrating Angular 4 earlier than that. It'll probably be in a separate branch and published as beta or something.

Thanks, Dan