Skip to content
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

Gracefully handle external modules in iife format #1623

Closed
Tracked by #1569
hyf0 opened this issue Jul 15, 2024 · 13 comments · Fixed by #1694, #1837 or #2328
Closed
Tracked by #1569

Gracefully handle external modules in iife format #1623

hyf0 opened this issue Jul 15, 2024 · 13 comments · Fixed by #1694, #1837 or #2328
Assignees

Comments

@hyf0
Copy link
Member

hyf0 commented Jul 15, 2024

No description provided.

@hyf0 hyf0 mentioned this issue Jul 15, 2024
4 tasks
@hyf0
Copy link
Member Author

hyf0 commented Jul 15, 2024

After #1622, there will be no panic if the input contains external modules while targeting iife format. But external imports are just striped away, which makes the output still not runnable. See #1624.

@hyf0
Copy link
Member Author

hyf0 commented Jul 15, 2024

@underfin Please describe how you gonna solve this issue before submitting an PR. I prefer how esbuild handle this, but the rollup's solution does show some advantages.

@hyf0
Copy link
Member Author

hyf0 commented Jul 15, 2024

How about we just keep generating imports from external modules

import ext from 'ext'
import { a } from 'ext'
console.log(ext, a, require('ext'))

become

import ext from 'ext'
import { a } from 'ext'

(function() {
  console.log(ext, a, require('ext'))
})()

Still follows the shits in, shits out principle.


esbuild's output

https://hyrious.me/esbuild-repl/?version=0.23.0&b=e%00entry.js%00import+ext+from+%27ext%27%0Aimport+%7B+a+%7D+from+%27ext%27%0Aconsole.log%28ext%2C+a%2C+require%28%27ext%27%29%29&o=--bundle+--format%3Diife+--external%3Aext+--outdir%3Ddist

(() => {
  var __create = Object.create;
  var __defProp = Object.defineProperty;
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  var __getOwnPropNames = Object.getOwnPropertyNames;
  var __getProtoOf = Object.getPrototypeOf;
  var __hasOwnProp = Object.prototype.hasOwnProperty;
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
    get: (a2, b) => (typeof require !== "undefined" ? require : a2)[b]
  }) : x)(function(x) {
    if (typeof require !== "undefined") return require.apply(this, arguments);
    throw Error('Dynamic require of "' + x + '" is not supported');
  });
  var __copyProps = (to, from, except, desc) => {
    if (from && typeof from === "object" || typeof from === "function") {
      for (let key of __getOwnPropNames(from))
        if (!__hasOwnProp.call(to, key) && key !== except)
          __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
    }
    return to;
  };
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
    // If the importer is in node compatibility mode or this is not an ESM
    // file that has been converted to a CommonJS file using a Babel-
    // compatible transform (i.e. "__esModule" has not been set), then set
    // "default" to the CommonJS "module.exports" for node compatibility.
    isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
    mod
  ));

  // entry.js
  var import_ext = __toESM(__require("ext"));
  var import_ext2 = __require("ext");
  console.log(import_ext.default, import_ext2.a, __require("ext"));
})();

rollup's output

https://rollupjs.org/repl/?version=4.18.1&shareable=JTdCJTIyZXhhbXBsZSUyMiUzQW51bGwlMkMlMjJtb2R1bGVzJTIyJTNBJTVCJTdCJTIyY29kZSUyMiUzQSUyMmltcG9ydCUyMGV4dCUyMGZyb20lMjAnZXh0JyU1Q25pbXBvcnQlMjAlN0IlMjBhJTIwJTdEJTIwZnJvbSUyMCdleHQnJTVDbmNvbnNvbGUubG9nKGV4dCUyQyUyMGElMkMlMjByZXF1aXJlKCdleHQnKSklMjIlMkMlMjJpc0VudHJ5JTIyJTNBdHJ1ZSUyQyUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTdEJTVEJTJDJTIyb3B0aW9ucyUyMiUzQSU3QiUyMm91dHB1dCUyMiUzQSU3QiUyMmZvcm1hdCUyMiUzQSUyMmlpZmUlMjIlMkMlMjJnbG9iYWxzJTIyJTNBJTdCJTdEJTdEJTJDJTIydHJlZXNoYWtlJTIyJTNBdHJ1ZSU3RCU3RA==

(function (ext) {
	'use strict';

	console.log(ext, ext.a, require('ext'));

})(ext);

@underfin
Copy link
Contributor

I would like using rollup way, it give a escape route for external module. Because the complete code of iife format should be like this.

var Module = (function(exports) {
    console.log(ext, ext.a, require('ext'));
    exports.value =1;
    return exports
})({}, ext)

The ext also could be configure by output.globals.

I'm try port it from here.

@hyf0
Copy link
Member Author

hyf0 commented Jul 15, 2024

Because the complete code of iife format should be like this.

Are you proposing

import ext from 'ext'
import { a } from 'ext'
console.log(ext, a, require('ext'))

should be transformed to ?

var Module = (function(exports) {
    console.log(ext, ext.a, require('ext'));
    exports.value =1;
    return exports
})({}, ext)

@underfin
Copy link
Contributor

underfin commented Jul 15, 2024

The original module should be

import ext from 'ext'
import { a } from 'ext'
console.log(ext, a, require('ext'))
export const value = 1;

@hyf0
Copy link
Member Author

hyf0 commented Jul 15, 2024

I do see the advantages of rollup's implementation. But I wonder the the real-world usage of exports and Module on case

var Module = (function(exports) {
    console.log(ext, ext.a, require('ext'));
    exports.value =1;
    return exports
})({}, ext)

Would be better if we some find some real-world use cases on iife output. I want to provide a most dx-friendly way to handle/inject external modules. Using global variables seems dirty in the fist glance.

@yyx990803
Copy link
Member

We should follow what Rollup does in this case.

@7086cmd
Copy link
Collaborator

7086cmd commented Jul 23, 2024

In Rollup, the parameters of the wrapper function vary depending on the situation, such as when we specify the output.exports option. If we specify the export value as named, it requires a parameter named exports, which is the return value after modification in an IIFE. External modules are also treated as parameters.

This is particularly relevant to the output.globals option, which specifies the global variable names for external modules in the browser. For example, when using electron, Rollup generates the following warning:

(!) Missing global variable names
https://rollupjs.org/configuration-options/#output-globals
Use "output.globals" to specify browser global variable names corresponding to external modules:
electron (guessing "electron")
electron (guessing "electron")

To elegantly support IIFE with output.exports, it is necessary to address this issue by ensuring the parameters are consistently specified.

@7086cmd
Copy link
Collaborator

7086cmd commented Jul 23, 2024

According to the conversation and Rollup's behavior, I handled the iife external modules and the output.globals in #1694.

github-merge-queue bot pushed a commit that referenced this issue Jul 23, 2024
In this PR, I addressed issues related to `output.exports`, particularly
for the `IIFE` format, and extended the solution to handle external
modules.

resolves #1623.
resolves #1569.

### Modifications

1. **Support for `output.globals` Key**: 
- Implemented support for the `{ [id: string]: string }` type in the
`globals` key.
- Note: Although Rollup supports both `{ [id: string]: string }` and
`((id: string) => string)`, this PR only includes support for the
former. Future PRs may add support for the function type.

2. **Arguments Handling for `IIFE` Format**: 
   - Adapted the handler function from `CJS`.
   - Utilized `filter_map` to identify and manage used external modules.
- Passed these modules to the `render_iife_arguments` function,
leveraging the `globals` key.
   - Open to suggestions for more elegant solutions.

### Tests

- Tests for `iife/external_modules` passed. (The actual behavior aligns
with rollup)
- Added new tests for `iife/external_modules_with_globals` and
JavaScript side tests.

---------

Co-authored-by: underfin <[email protected]>
@underfin underfin reopened this Jul 23, 2024
@underfin
Copy link
Contributor

underfin commented Jul 23, 2024

#1694 (comment) need to do

github-merge-queue bot pushed a commit that referenced this issue Aug 6, 2024
resolves #1836.
resolves #1623.

I modified the `renamer` and checked if it wasn't `esm`. Since named
exports are not allowed using `default` or `none`, we should always
consider it as a reserved key.

> #1694 (comment)
need to do
> 
> From #1623.

---------

Co-authored-by: IWANABETHATGUY <[email protected]>
github-merge-queue bot pushed a commit that referenced this issue Aug 6, 2024
resolves #1836.
resolves #1623.

I modified the `renamer` and checked if it wasn't `esm`. Since named
exports are not allowed using `default` or `none`, we should always
consider it as a reserved key.

> #1694 (comment)
need to do
> 
> From #1623.

---------

Co-authored-by: IWANABETHATGUY <[email protected]>
@hyf0 hyf0 closed this as completed in #1837 Aug 6, 2024
@underfin underfin reopened this Aug 7, 2024
@github-actions github-actions bot added the stale label Sep 7, 2024
@7086cmd
Copy link
Collaborator

7086cmd commented Sep 14, 2024

Is there a specific action we need to take in response to right now?

@github-actions github-actions bot removed the stale label Sep 15, 2024
github-merge-queue bot pushed a commit that referenced this issue Sep 26, 2024
<!-- Thank you for contributing! -->

### Description

close #1623
<!-- Please insert your description here and provide especially info
about the "what" this PR is solving -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment