dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.2k stars 1.57k forks source link

dartdevc.bat on windows crashes when using rxdart ^0.23.1 #40947

Closed MagicPoulp closed 4 years ago

MagicPoulp commented 4 years ago

This tracker is for issues related to:

repro step: install chocolatey on Windows install dart using choco: choco install -y dart-sdk

make a new dart project with this pub.yaml

name: bloc
description: Bloc Dart package.
version: 0.0.1
author:
homepage:

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
  rxdart: ^0.23.1
  tuple: ^1.0.3
  meta: ^1.1.8

dev_dependencies:

get packages C:\tools\dart-sdk\bin\pub.bat get

here is how the file structure looks like: ./.packages ./lib ./lib/main.dart ./pubspec.lock ./pubspec.yaml

Running a compilation crashes: And if I comment the import of rxdart the crash disappears C:\tools\dart-sdk\bin\dartdevc.bat lib\main.dart -o dart_bundle.js

here is the crash: We're sorry, you've found a bug in our compiler. You can report this bug at: https://github.com/dart-lang/sdk/issues/labels/web-dev-compiler Please include the information below in your report, along with any other information that may help us track it down. Thanks! dartdevc arguments: --dart-sdk=C:\tools\dart-sdk lib/bloc.dart --modules es6 -o dist/dart_bundle.js dart --version: 2.7.1 (Thu Jan 23 13:02:26 2020 +0100) on "windows_x64"


Unsupported operation: tried to generate an unreachable node: `extension ConnectableStreamExtensions<T> on Stream<T> {ConnectableStream<T> publish() => PublishConnectableStream<T>(this); ValueConnectableStream<T> publishValue() => ValueConnectableStream<T>(this); Value
nnectableStream<T> publishValueSeeded(T seedValue) => ValueConnectableStream<T>.seeded(this, seedValue); ReplayConnectableStream<T> publishReplay({int maxSize}) => ReplayConnectableStream<T>(this, maxSize: maxSize); Stream<T> share() => publish().refCount(); ValueStrea
T> shareValue() => publishValue().refCount(); ValueStream<T> shareValueSeeded(T seedValue) => publishValueSeeded(seedValue).refCount(); ReplayStream<T> shareReplay({int maxSize}) => publishReplay(maxSize: maxSize).refCount();}`
#0      CodeGenerator._unreachable (package:dev_compiler/src/analyzer/code_generator.dart:6293:5)
#1      CodeGenerator.visitExtensionDeclaration (package:dev_compiler/src/analyzer/code_generator.dart:6678:59)
#2      ExtensionDeclarationImpl.accept (package:analyzer/src/dart/ast/ast.dart:3819:49)
#3      CodeGenerator.visitCompilationUnit (package:dev_compiler/src/analyzer/code_generator.dart:564:30)
#4      List.forEach (dart:core-patch/array.dart:112:8)
#5      CodeGenerator.compile (package:dev_compiler/src/analyzer/code_generator.dart:319:22)
#6      compileWithAnalyzer (package:dev_compiler/src/analyzer/module_compiler.dart:108:33)
#7      _compile (package:dev_compiler/src/analyzer/command.dart:152:16)
#8      compile (package:dev_compiler/src/analyzer/command.dart:56:18)
#9      compile (package:dev_compiler/src/compiler/shared_command.dart:410:18)
#10     main (file:///C:/b/s/w/ir/cache/builder/sdk/pkg/dev_compiler/bin/dartdevc.dart:32:24)
#11     _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:303:32)
#12     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
sigmundch commented 4 years ago

@MagicPoulp thanks for your bug report!

Sorry in advance for the long answer.

As surprising as this may sound, this is working as intended.

We did a migration in dartdevc to use a different frontend, and with the default set of flags you seem to be using the old frontend. If you pass --kernel to the command-line arguments, you may bypass this error by using the new frontend. In 2.8 the old frontend has been deleted and the new one is run by default.

That being said, we generally recommend that you don't invoke dartdevc directly on the command line. Dart ships with 2 compilers for javascript, one meant to build applications so you can ship them (dart2js) and the other (dartdevc) is meant for development behind a development server. The latter is a modular compiler that requires carefully building separate modules based on the dependencies in your app. Because of that, we recommend invoking dartdevc indirectly via build tools like webdev. The latest version of webdev knows how to invoke dartdevc to use the correct set of flags, so this issue wouldn't have been visible under that workflow.

One general benefit of using webdev with dartdevc is that it is designed to support your edit/refresh cycle: when using webdev serve, you can iterate on edits and when you refresh your app, only the modules that were modified will be recompiled.

Hope this clarifies things a bit.

MagicPoulp commented 4 years ago

Thanks for the detailed answer.

I am on linux, but our build server is on windows. I installed dart-sdk with chocolatey and maybe the version was old (2.7.1) (if you say the new kernel should be active by default).

I tried on cygwin to use a linux based dartdevc but it does not work. The file is too much for Cygwin to run. It complains about the file format, and I don't think it is carriage return related (not sure) because when it did in a powershell it mentionen the \r, but not in Cygwin. I think Cygwin is not a real linux on many aspects.

I tried webdev and also dart2js directly. dart2js does not support the option --modules es6 that I need.

So fart dartdevc seems to be able to generated working javascript. Just one minor issue. It exports window instead of $window (then why would there not be more similar error?). I did not have "the energy" the need to create a reproducible new issue but it is a real one.

update. I create an issue for it: https://github.com/dart-lang/sdk/issues/40976

dartdevc --modules es6 -o dart_bundle.js

Many blogs around say one can use dart-angular and reuse the code in flutter and web. I went one step further. I am using dart to generate es6 Javascript that is then used with a strongly typed interface in the vanilla Typescript Angular. I prefer the vanilla Angular.

A barrel file (to help angular compilation) imports the file generated by dart. The barrel file looks like this:

import { InjectionToken, } from '@angular/core';

import { srcbase_bloc as BaseBloc, srcpagesimage_galleryimage_gallery_bloc as imageGalleryObject, // @ts-ignore } from 'GenericFrontEndBlocAngularBundle/dart_bundle';

/ Exporting helps the production build to find types /

// @Injectable is not needed because it is an alias for @Inject // applied to the contructor's arguments class ImageGalleryBloc extends imageGalleryObject.ImageGalleryBloc {}

interface ImageGalleryBlocIf { currentViewStream: any; showImagesList: any; showImageDetails: any; backButtonMoveToNextView: any; }

// interfaces require an injection token as mentioned here: // https://stackoverflow.com/questions/45570484/how-to-enforce-component-service-interface-in-angular?rq=1 const imageGalleryBlocToken = new InjectionToken('imageGalleryBlocToken');

export { // eslint-disable-next-line no-undef BaseBloc, ImageGalleryBloc, ImageGalleryBlocIf, imageGalleryBlocToken, };


And here is how it is provided in a component:

providers: [ // dart_sdk.js:5042 says we should use new class.new() to create a dart object // eslint-disable-next-line new-cap { provide: imageGalleryBlocToken, useFactory: () => new (ImageGalleryBloc as any).new() }, ],

Besides the generated script, one needs es6/dart_sdk.js from the dart-sdk.

MagicPoulp commented 4 years ago

this below worked and the compilation of rxdart worked: choco install 2.8.0.13-dev-0

MagicPoulp commented 4 years ago

If you know a place where I can document the dart generation for vanilla Angular (not dart angular), please tell me. I could also make a working code sample.

it is awsome because there is no need of @JS decorators.

And I do not care if dartdevc is in dev mode because I bundle it in my webpack minified bundle.

THe main issue is the size of the dart_sdk.js. BUt it is acceptable.

sigmundch commented 4 years ago

Thanks for sharing about your experience. That's a very unique setup you have!

I want to make sure you are aware of the risk with this setup. Since this is not what we've designed dartdevc to do, we may accidentally or purposely make breaking changes that could affect you. Our goal is to make dartdevc a good experience for fast iteration cycle during development, and we do not support using its output directly as an input to a larger JavaScript application. Just to name one example, we currently support the es6 module format, but we have plans to consolidate into a single module format. Given some constraints we have with support for hot-reload in flutter, this format is unlikely going to be es6, so there is a possibility that we may drop that as a supported format.

For these reasons, I would like to encourage you to invest now in a more stable approach that is well supported. Our recommended approach for interoperability with JavaScript is to use the package:js APIs, which you can use to explicitly expose your dependencies. That approach will enable you to use dart2js to bundle your code and combine it with other JavaScript modules if you like, since at that point you are in control of how the JavaScript we generate is embedded and exposed as a module in the context of a bigger app.

MagicPoulp commented 4 years ago

OK thanks for the good info.

Yes I will try to use dart2js and package:js.

I already made a PR in the popular blog repo for flutter + dart-angular with rxdart. https://github.com/budo385/todo_bloc_app/pull/12

I will add an example for flutter + typescript-angular when I have sorted out how.

Even if they fix flutter-web in a few years, it will be a very special thing with its own rendering engine. typescript-angular has millions of code samples and components.

MagicPoulp commented 4 years ago

Any idea why does the rx doc says stream is a ValueStream whereas in the source code it is a Stream from libdart? https://pub.dev/documentation/rxdart/latest/rx/BehaviorSubject-class.html

~/.pub-cache/hosted/pub.dartlang.org/rxdart-0.23.1$ e lib/src/subjects/behavior_subject.dart: class BehaviorSubject extends Subject implements ValueStream { _Wrapper _wrapper;

BehaviorSubject._( StreamController controller, Stream stream, this._wrapper, ) : super(controller, stream);

MagicPoulp commented 4 years ago

I found why. A BehaviorSubject extends ValueStream. And the stream property is a Stream. They jsut have a typo in the doc.

Concerning your comment that you may decide to support only a certain format and not es6. You should know that es6 can run faster in modern browsers than es5, and bundles become smaller.

MagicPoulp commented 4 years ago

Help with the problem below is appreciated.

with dartdevc, I could compile,

with dart2js, it first complains there is no main function defined. Even with an empty main file, it does not compile my library.

This is my file, and the library in question contains a class that is exported.

import 'package:bloc/bloc.dart';

void main() { }

Perhaps dart2js require a complete program in the main function? I cannot export stuff?

MagicPoulp commented 4 years ago

Still trying. I found a good example in the sass package. Unfortunately package:js requires dark_sdk < 2.

node.dart: /// The entrypoint for the Node.js module. /// /// This sets up exports that can be called from JS. void main() { exports.render = allowInterop(_render); exports.renderSync = allowInterop(_renderSync); exports.info = "dart-sass\t${const String.fromEnvironment('version')}\t(Sass Compiler)\t" "[Dart]\n" "dart2js\t${const String.fromEnvironment('dart-version')}\t" "(Dart Compiler)\t[Dart]";

MagicPoulp commented 4 years ago

If I have to use dart version 1 for the package js, I think I should stick to dartdevc and freeze my version of dart-sdk 2.8.

update. I think I was wrong. the very latest js package works with dart 2.

MagicPoulp commented 4 years ago

I could compile something but the output has 2 problems.

first it does not fetch the content of the class ImageGalleryBloc. second, it makes a global function that will contain everything, it does not just generates code that can be imported by a larged JS application.

here is the code. If you compile the code below, the function showImagesList and the expression HERE cannot be found in the generated code.

[https://github.com/dart-lang/sdk/issues/41028] https://github.com/dart-lang/sdk/issues/41028

And I have an anomaly because I use allowINterrop on a class. Allowinterrop is made to maek a function accessible by Javascript.

So you say you support dart2js more. But dartdevc works outof the box wihtout needing to use package:js. It really seems like package:js can only export functions. Maybe there is a way to export a class, but it will be very sophisticated.