Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rollup.js how import a js file (not es6 module) without any change (myvar$extrastring)

First of all, i understand why rollup.js need to append extra string at the end of certain variable to avoid collision but... I don't understand how to "concat/import" a simple javascript file who is not an amd/commonjs/es6, but simple revealing module !

I have the following file structure:

foo.js

var Foo = (function () {

    var someMethod = function () {};

    return {
        someMethod: someMethod
    };

})();

bar.js

(function(module) {

    module.bar = "bar";

})(Foo);

main.js

import "foo.js"
import "bar.js"

after building, i got:

build.js

var Foo$1 = (function () { // Here the problem

    var someMethod = function () {};

    return {
        someMethod: someMethod
    };

})();

(function(module) {

    module.bar = "bar";

})(Foo); // Ouupss !

So how can i got Foo instead of Foo$1 ? Or Foo$1 instead of Foo for bar.js ?

Edit:

In case, where in main.js, i use default import in view to override the default name:

import Foo from "foo.js"

i got an error like this (normal !):

Non-existent export 'default' is imported from foo.js by main.js

It's a misunderstanding, but after research on stackoverflow and internet i found nothing about how can i resolve this tricky problem.

So... thanks in advance !

like image 293
Tristan Avatar asked Nov 12 '16 22:11

Tristan


2 Answers

Rollup doesn't concatenate JavaScript files; it transpiles a set of ES2015 modules into a functionally equivalent single script. ES2015 modules don't function quite like modules in most other languages (certainly not like C/C++ #includes!), and I recommend reading about them here. If you want to import a regular JavaScript file, you'll have to convert it to an ES2015 module, which in a pinch can be done automatically using a Rollup plugin. For instance, this is a poor general solution, but you could put something like this in your rollup.config.js:

import replace from 'rollup-plugin-replace';

export default {
  entry: './src/main.js',
  dest: './dist/bundle.js',
  plugins: [
    replace({
      include: './src/main.js',
      values: {
        'var Foo =': 'export default'
      }
    })
  ]
};

Perhaps there should be a plugin to automatically export things, but there doesn't seem to be one.

ES2015 modules don't share scope. Thus, when you declare a variable Foo in foo.js, that variable doesn't exist in bar.js. When you try to access a variable called Foo in bar.js, it looks it up as a global variable, as if you hadn't declared it in any file. By renaming foo.js's Foo to Foo$1, Rollup is ensuring correct behavior by preventing foo.js's local Foo from shadowing the global Foo.

In order to share data between modules, you need to export things. Here's one way to rewrite your example:


foo.js

export default (function () {

    var someMethod = function () {};

    return {
        someMethod: someMethod
    };

})();

bar.js

import module from './foo.js';

module.bar = "bar";

main.js

import "./bar.js"

But that code doesn't utilize modules very well. You'd be more likely to write something like this:


foo.js

export function someMethod () {}

bar.js

export { someMethod } from './foo.js';

export const bar = "bar";

main.js

import * as Bar from "./bar.js";

Because Rollup can infer more about how code is used when it's shared via imports and exports, it can make more intelligent decisions about which code must be kept and which can be discarded in the output without affecting functionality. This is demonstrated by the fact that it outputs no code at all for the second example. Neither one actually does anything, but Rollup can't be sure about the first one because it does complicated things with its data instead of just using exports.

like image 195
Permutator Avatar answered Oct 21 '22 12:10

Permutator


While Permutators answer is stil true for the most part, there is now a plugin called rollup-plugin-legacy. It lets you wrap some arbitrary JS lib into a module usable with rollup. I don't know why it is so little known, because I find it super useful.

Just add it as a plugin:

legacy({
      "foo.js": "Foo"
})

And change your import statement in main.js to:

import Foo from 'foo.js'
like image 40
JepZ Avatar answered Oct 21 '22 11:10

JepZ