sdk icon indicating copy to clipboard operation
sdk copied to clipboard

[web] [DDC] TypeError: Cannot read properties of undefined (reading 'new')

Open AlexV525 opened this issue 1 year ago • 14 comments
trafficstars

This tracker is for issues related to:

  • Dart native and web compilers
  • Dart VM

Upstream: https://github.com/cfug/dio/issues/2282

We've split our Dio adapter with conditional imports. However, writing the caller in a specific way does not reference the correct constructor as I can tell.

Consider the example, running this on Flutter Web environment will unexpectedly throw TypeError: Cannot read properties of undefined (reading 'new'):

main.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

import 'adapter.dart';

void main() {
  try {
    final adapter = makeHttpClientAdapter();
    print(adapter);
  } on Object catch (error) {
    print(error);
  }

  runApp(const MyApp());
}
adapter.dart
import 'package:dio/dio.dart';

import 'client_adapter_io.dart'
    if (dart.library.js_interop) 'client_adapter_web.dart' as adapter;

HttpClientAdapter makeHttpClientAdapter() => adapter.makeHttpClientAdapter();
adapter_io.dart
import 'package:dio/dio.dart';
import 'package:dio/io.dart';

HttpClientAdapter makeHttpClientAdapter() {
  return IOHttpClientAdapter();
}
adapter_web.dart
import 'package:dio/browser.dart';
import 'package:dio/dio.dart';

HttpClientAdapter makeHttpClientAdapter() {
  return BrowserHttpClientAdapter()..withCredentials = true;
}

Workaround

HttpClientAdapter makeHttpClientAdapter() {
  final adapter = HttpClientAdapter() as BrowserHttpClientAdapter;
  adapter.withCredentials = true;
  return adapter;
}

AlexV525 avatar Aug 16 '24 11:08 AlexV525

Summary: The issue is a TypeError thrown when using conditional imports with Dio on Flutter Web. The error occurs because the correct constructor for the HttpClientAdapter is not being referenced due to the way the caller is written.

dart-github-bot avatar Aug 16 '24 11:08 dart-github-bot

@Rexios80 Do you have any clues what is going on here? 🤔

AlexV525 avatar Aug 16 '24 12:08 AlexV525

What dart/flutter version? There might be some fixes that still aren't merged into stable.

Rexios80 avatar Aug 16 '24 14:08 Rexios80

@Rexios80 im faced this:

[✓] Flutter (Channel stable, 3.22.2, on macOS 14.5 23F79 darwin-arm64, locale en-RU)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.2)
[✓] VS Code (version 1.92.2)
[✓] Connected device (5 available)
[✓] Network resources

Dan-Crane avatar Aug 16 '24 14:08 Dan-Crane

Can you reproduce on flutter master?

Rexios80 avatar Aug 16 '24 14:08 Rexios80

This also happens on master 3.24.0-1.0.pre.606

Dan-Crane avatar Aug 16 '24 14:08 Dan-Crane

Is it the cascade that's causing the issue?

Rexios80 avatar Aug 16 '24 17:08 Rexios80

Is it the cascade that's causing the issue?

Nope. Removing it doesn't help.

AlexV525 avatar Aug 16 '24 17:08 AlexV525

You say this is a workaround:

HttpClientAdapter makeHttpClientAdapter() {
  final adapter = HttpClientAdapter() as BrowserHttpClientAdapter;
  adapter.withCredentials = true;
  return adapter;
}

What about this fixes the issue if it's not removing the cascade? Is it the cast?

Rexios80 avatar Aug 16 '24 17:08 Rexios80

You say this is a workaround:

HttpClientAdapter makeHttpClientAdapter() {
  final adapter = HttpClientAdapter() as BrowserHttpClientAdapter;
  adapter.withCredentials = true;
  return adapter;
}

What about this fixes the issue if it's not removing the cascade? Is it the cast?

Yes, creating the adapter like this and force cast it does work, it's not about the cascade. The workaround is to help people to achieve their goal.

AlexV525 avatar Aug 16 '24 18:08 AlexV525

Which of the web environments are you experiencing this issue?

  • Production JavaScript (dart2js compiler)
  • Production WASM (dart2wasm compiler)
  • Development (DDC compiler)

nshahan avatar Aug 16 '24 18:08 nshahan

Which of the web environments are you experiencing this issue?

  • Development (DDC compiler)

The DDC compiler. The built Web application does not run into the issue.

AlexV525 avatar Aug 17 '24 01:08 AlexV525

@nshahan - I recall we've seen an error with this message before long ago, but we didn't have a repro at hand. Maybe they are related? (see https://github.com/dart-lang/sdk/issues/50380)

sigmundch avatar Aug 19 '24 17:08 sigmundch

I actually have this error in one of my projects now. Not sure how it took me this long to notice. The workaround provided by @AlexV525 does fix the issue.

Rexios80 avatar Aug 27 '24 20:08 Rexios80

This is getting worse according to https://github.com/cfug/dio/issues/2282#issuecomment-2567611491

@nshahan @sigmundch Would you mind taking further investigations?

AlexV525 avatar Jan 11 '25 08:01 AlexV525

I'm getting this error using:

Flutter 3.29.0 • channel stable • https://github.com/flutter/flutter.git Framework • revision 35c388afb5 (4 days ago) • 2025-02-10 12:48:41 -0800 Engine • revision f73bfc4522 Tools • Dart 3.7.0 • DevTools 2.42.2

I'm not even using conditional imports or anything. Simply trying to use BrowserHttpClientAdapter() at all throws this error.

ryanovas avatar Feb 15 '25 02:02 ryanovas

I have a fix in progress but to summarize the issue: package:dio has a dependency on package:dio_web_adapter. Both packages include a file called package:<pkg_name>/browser.dart. package:dio/browser.dart is the library that contains BrowserHttpClientAdapter.

DDC compiles libraries modularly but it can sometimes combine libraries from different packages into the same JS module. In this case both package:dio_web_adapter/browser.dart and package:dio/browser.dart are getting compiled into the same JS module. DDC then tries to create an import/export nickname for each library in the module but gives both the same nickname. So due to this bug when adapter_web.dart imports package:dio/browser.dart, it ends up importing package:dio_web_adapter/browser.dart instead. This is why BrowserHttpClientAdapter seems to be missing.

The workaround to use HttpClientAdapter() instead calls a constructor from a different library, one that doesn't have a naming collision so we can successfully access it from adapter_web.dart. It then calls through to the BrowserHttpClientAdapter constructor from within the same module. Since the call is within the same JS module, the import nickname doesn't matter and so the code for HttpClientAdapter is successfully able to call BrowserHttpClientAdapter().

biggs0125 avatar Feb 18 '25 17:02 biggs0125

A quick update here. The fix has landed in the Dart SDK and is rolled into the Flutter SDK master channel. Please feel free to try it out on the master channel.

We're considering the fix medium to high risk given it changes how DDC imports and exports libraries. We want to give the change a chance to be tested in earlier channels before it gets into stable.

Given this package:dio example is the only example we've heard of triggering this issue and given there is a simple workaround, we've decided not to cherrypick the fix. We ask that anyone hitting this issue use the workaround above.

In production builds the code produced by the workaround should be nearly identical to that produced by the broken pattern. So there should be no performance implications to the workaround.

@AlexV525 Thank you for filing this and providing a workaround.

biggs0125 avatar Feb 20 '25 20:02 biggs0125

I can confirm the issue was resolved with that rolled commit. @biggs0125 Thanks for the fix!

AlexV525 avatar Feb 25 '25 05:02 AlexV525