angular-cli icon indicating copy to clipboard operation
angular-cli copied to clipboard

enable serve with esbuild

Open robertIsaac opened this issue 2 years ago • 8 comments

Command

serve

Description

with the new application builder, you build using esbuild but serve using vite we are having a problem after trying to migrate to the new application builder and it only happen when we deploy but not when we serve it locally (trying to read something of undefined error) I know there is a --watch option for build, but it doesn't serve and we have a proxy configuration so trying to make it work using watch is complicated and it shouldn't be

Describe the solution you'd like

during serve to have option --builder which can be esbuild, I imagine it will be slower but it will be very beneficial to debug errors related to esbuild at least during the migration phase till the webpack support is dropped and everyone is using esbuild

Describe alternatives you've considered

another approach is for the build command to have option --serve and --proxy options it doesn't need to have the auto refresh and all of the features that serve has, just basic serving of the application

robertIsaac avatar Jan 17 '24 11:01 robertIsaac

During ng serve vite is used soley as a web server, under the hood esbuild is still used to build and bundle the application code.

Does the error occur when using ng serve --configuration production?

alan-agius4 avatar Jan 17 '24 11:01 alan-agius4

we are using nx not ng, and it doesn't have production in the configuration for serve can you give me the list of the configuration that I should change?

FYI I found the problem finally this.autoTable = await import('jspdf-autotable').then((library) => library.default); here for some reason now library.default doesn't return the function that is exported, but the object, so I need to add another .default

    this.autoTable = await import('jspdf-autotable').then(
      (library) =>
        (
          library.default as unknown as {
            default: (pdf: jsPDFDocument, options: UserOptions) => void;
          }
        ).default,
    );

but because of typing error I need to write the typing myself

robertIsaac avatar Jan 17 '24 12:01 robertIsaac

Below is the configuration for server in production

"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "configurations": {
    "production": {
      "buildTarget": "<project-name≥:build:production"
    },
    "development": {
      "buildTarget": "<project-name≥:build:development"
    }
  },
  "defaultConfiguration": "development"
},

alan-agius4 avatar Jan 17 '24 13:01 alan-agius4

Below is the configuration for server in production

"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "configurations": {
    "production": {
      "buildTarget": "<project-name≥:build:production"
    },
    "development": {
      "buildTarget": "<project-name≥:build:development"
    }
  },
  "defaultConfiguration": "development"
},

no the error doesn't exist here I will try to reproduce it in a new Angular 17 project and share it

robertIsaac avatar Jan 17 '24 15:01 robertIsaac

here is a reproduce for the problem https://github.com/robertIsaac/jspdf-autotable-error-reprod on ng serve and ng serve --configuration production it show function which is expected but if you run ng b then npx serve .\dist\jspdf-autotable-error-reprod\browser\ it will show object which what causes the problem you can also take a look at the console to see what exactly is autoTable

robertIsaac avatar Jan 17 '24 15:01 robertIsaac

beside the new feature, should I open a bug for that here or in esbuild? or is it working as expected with esbuild?

robertIsaac avatar Jan 17 '24 15:01 robertIsaac

This is expected behavior. You can read more about the error prone nature of default exports and CommonJS libraries here: https://esbuild.github.io/content-types/#default-interop The jspdf-autotable package does have an ESM variant of the code that is published inside the package. Many packages use exports conditions to allow bundlers to automatically pick the appropriate code. However, this package is setup in a way that requires manually opting in to its usage via an import to jspdf-autotable/es. Using this import should alleviate the problem. The ESM code is also roughly 10KB smaller as well.

clydin avatar Jan 17 '24 16:01 clydin

This is expected behavior. You can read more about the error prone nature of default exports and CommonJS libraries here: https://esbuild.github.io/content-types/#default-interop The jspdf-autotable package does have an ESM variant of the code that is published inside the package. Many packages use exports conditions to allow bundlers to automatically pick the appropriate code. However, this package is setup in a way that requires manually opting in to its usage via an import to jspdf-autotable/es. Using this import should alleviate the problem. The ESM code is also roughly 10KB smaller as well.

This a great solution, but I have a question, why the import behavior is different in serve than build? Can there be more diverge in the code and find unexpected bugs when I build or it only affects the commonjs libraries?

robertIsaac avatar Jan 17 '24 20:01 robertIsaac

It differs because Vite adjusts the imports of CommonJS (CJS) modules to directly expose the default. You can find more details at: https://github.com/vitejs/vite/blob/947aa53bb8ea60ce03a207421a6e7a4117385e58/packages/vite/src/node/plugins/importAnalysis.ts#L873

Regarding divergences, a development app aims to closely mimic a production application, but it's not an exact replica. When building for production, factors such as dead-code elimination and side-effectful code can alter the app's behavior. However, such cases are relatively uncommon.

This issue is being closed as the implementation of a different development server, specifically esbuild serve, is not currently not in the roadmap.

alan-agius4 avatar Jan 18 '24 08:01 alan-agius4

This is expected behavior. You can read more about the error prone nature of default exports and CommonJS libraries here: https://esbuild.github.io/content-types/#default-interop The jspdf-autotable package does have an ESM variant of the code that is published inside the package. Many packages use exports conditions to allow bundlers to automatically pick the appropriate code. However, this package is setup in a way that requires manually opting in to its usage via an import to jspdf-autotable/es. Using this import should alleviate the problem. The ESM code is also roughly 10KB smaller as well.

hi @clydin jspdf-autotable/es doesn't exist which version of jspdf-autotable are you talking about?

robertIsaac avatar Jan 23 '24 10:01 robertIsaac

@robertIsaac, the ./es is defined as an entry-point through the package exports. See: https://unpkg.com/browse/[email protected]/package.json

alan-agius4 avatar Jan 23 '24 10:01 alan-agius4

it doesn't work still

- Building...X [ERROR] TS2307: Cannot find module 'jspdf-autotable/es' or its corresponding type declarations. [plugin angular-compiler]

    packages/web/src/app/widgets/export/builders/pdf-file-builder.ts:73:34:
      73 │     this.autoTable = await import('jspdf-autotable/es').then(

robertIsaac avatar Jan 23 '24 12:01 robertIsaac

@alan-agius4 @clydin I have updated the repo https://github.com/robertIsaac/jspdf-autotable-error-reprod to include the latest version of jspdf-autotable and trying to use jspdf-autotable/es if I'm doing something wrong please let me know

robertIsaac avatar Jan 23 '24 12:01 robertIsaac

@robertIsaac looks like you are using an version 3.5.23 of jspdf-autotable which does not expose /es as an entry-point.

See: https://github.com/robertIsaac/jspdf-autotable-error-reprod/blob/c0c1e960e5b9d11918534d9ec8d4bc6e7c8df484/package-lock.json#L7683-L7690

alan-agius4 avatar Jan 23 '24 12:01 alan-agius4

I'm sorry I forget to push

robertIsaac avatar Jan 23 '24 12:01 robertIsaac

So for package exports to be resolved, the module and resolution options in TypeScript config need to be set to Node16 or NodeNext. This however would break other things.

As a workaround could ignore the TS error by doing the following;

// @ts-expect-error
this.autoTable = await import('jspdf-autotable/es').then((library) => library.default);

I would suggest that you however an issue with the author of jspdf-autotable so that they implement a package export option which is transparent for the consumer and the bundler/runtime can pick up the right variant of the code.

  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
+     "import": "./dist/jspdf.plugin.autotable.mjs",
      "default": "./dist/jspdf.plugin.autotable.js"
    },
    "./es": { // They could potentially deprecate this. 
      "types": "./dist/index.d.ts",
      "default": "./dist/jspdf.plugin.autotable.mjs"
    }
  },

alan-agius4 avatar Jan 23 '24 13:01 alan-agius4

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.