I am using 2 modules, that are using "window.ModuleName" to export themself. Both of them use the same ModuleName.
window.z = a;
window.z = b
The first module a is standalone module, as I am importing it through $.getScript, when it is needed.
The second module b is bundled through webpack.
Module a window.z overwrite module b window.z when is loaded. Therefore, I would like to change the scope of the module b by assigning it to a variable or a namespace with webpack instead of window scope through webpack or any other possibility.
newScope.z = a
Both modules are not defined by me, therefore, I cannot change the export.
Is there any way to do that in professionally?
create a startup.js file (to be included/required before you need a or b) where you do this:
require('a')
var z1 = window.z
window.z1 = z1
require('b')
now window.z1 is the a.z, and window.z is b.z, yo have them both
I could only solve that through using string replace loader from webpack and replace the export of module b from window.z => window.zb.
Unfortunately it seems there is no possibility to change the scope of a variable from window global object to local one.
Related
What exactly is the difference between usedExports in optimization of webpack config and sideEffects in package.json?
These are two different things.
About the usedExports:
Consider this as an instruction to Webpack to allow it to do two things:
Allow the exported identifiers to be renamed to shorter version (name mangling), By default, during the bundling process, the exported modifiers are not renamed.
Allow unused exports to be not exported from a module. By default, all the exported identifiers (variables, functions, classes, etc.) are exported even if those are not used anywhere in code.
For example, in the code
// MODULE A
export const myVariable = 10;
export const myFunction1 = () => a1;
export const myFunction2 = () => a2();
// MODULE B
import { myVariable } from './a.js';
// MODULE C
import { myFunction1 } from './a.js';
With this flag enabled, in above code, since myFunction2 is not used anywhere in the code, it would not be exported when the a.js module is being exported. Next thing it would probably try is to rename myVariable to single letter identifier like a and myFunction1 to b or similar. This applies to not just the modules you have authored but also the modules from node_modules as well.
About the sideEffects:
Although module bundler like webpack is smart enough to figure out if there are side effect in a given module, providing explicit sideEffects hints adds more confidence for bundler.
When doing the production bundling, the sideEffects and usedExports is used only if optimization.providedExports flag is enabled.
I have declared a variable in one module like this:
// first.js
var folder;
export {folder};
and I want to use it from a different module, like this:
// second.js
import { folder} from '../js/first.js';
folder = gui.addFolder( 'Avatar Measurements' );`
TypeError: Assignment to constant variable.
Imports are read-only live bindings to the original variable in the exporting module. The "read-only" part means you can't directly modify them. The "live" part means that you can see any modifications made to them by the exporting module.
If you have a module that needs to allow other modules to modify the values of its exports (which is/should be rare), it needs to export a function that does that. For instance:
a.js:
export let folder;
export function setFolder(f) {
folder = f;
}
b.js:
import { folder, setFolder } from "./a.js";
console.log(folder); // This will be `undefined` unless another module has already modified it
setFolder(gui.addFolder("Avatar Measurements"));
console.log(folder); // This will be whatever `gui.addFolder` returns
Again, though, it is/should be very rare for a module to allow other modules to modify its exports that way.
In the comments you asked me for an example of exporting an object for this instead:
a.js:
export let shapes = {};
b.js:
import { shapes } from "./a.js";
shape.folder = gui.addFolder("Avatar Measurements");
But it's not clear to me why that object needs to live in a rather than just being local in b.
That happens because you are creating a folder constant when importing folder from ../js/first.js. You cannot reassign a value to any constant, including folder. Don't use == or ===, as those are comparasion operators and don't change the value of folder.
If you want to pass information from second.js to first.js, consider exporting a function from second.js. If you don't, then use another name for a variable, like folder_ (don't forget to declare it first: var folder_;).
Imagine two javascript files and one entry point file:
app.js:
require(a.js);
require(b.js);
a.js:
var a = 4;
b.js:
var b = a+1;
console.debug(b);
This unfortunately does not work because the context of file a is lost in file b, meaning b.js does not know of any variable called a.
How can I fix that using Webpack - I simply want get the same result as
<script src="a.js"></script>
<script src="b.js"></script>
with the added effect of bundling through Webpack.
Using ES2015 modules (which may not be available for you, you can use require instead)
a.js:
export var a = 4;
b.js
import { a } from "./b.js";
var b = a+1;
console.debug(b);
Webpack is a module building/bundling system that works by creating UMD (universal modules) from javascript files. You have to import/export these modules in order for them to be in scope.
This is b.js
var something = "hooorraaaaay!!!";
And this is a.js
require( './b.js' );
console.log(something);
Why isn't something being recognised within a.js. I understand that it has been declared with var, but my understanding is that any variable declared outside a function should act global. So why isn't this working?
Node modules are each in their own scope. By default, nothing in module a is visible to module b. Doing a require() on a module is NOT like including the source. It loads the file runs the code and then the only things that are available to the outside world are:
Any functions or properties that are explicitly exported from the module by assigning to module.exports.
Any functions or properties that are explicitly assigned to the global object in node.
So, if you want something in b.js to be exposed to the outside world, you do like this:
// b.js
module.exports.callMe = function() {
console.log("I'm in module b");
}
And, then in a.js, you can do this:
// a.js
var b = require('./b.js');
b.callMe();
This is how the module system works in node.js. It is very different than just including a <script> tag in a browser web page. You can read more about the module system in these references:
Understanding module.exports and exports in Node.js
What is the purpose of Node.js module.exports and how do you use it?
Node.js Handbook - How require() Actually Works
Internally, node.js loads a module's code and then inserts it into a wrapper function. So, each top level variable in a node module is actually only a local variable in that module function. This is why nothing is globally declared or shared by default. It is done this way on purpose so that each module comes with it's own private area for storing it's state and will not, by default, interfere with the variables of any other module.
You then explicitly export only the property/function interfaces that you want to make public and even then, they are still not exported as public symbols so again they cannot conflict with anything else.
So, the b.js code above actually gets transformed into this when node.js runs it:
(function (exports, module, require, __filename, __dirname){
module.exports.callMe = function() {
console.log("I'm in module b");
}
})(...);
The (...) contains actual variables that are passed to the module.
Let me assume you are using node.js judging from the require function.
node.js wraps each file in its own scope. this has nothing to do with the use of var keyword. every file in node.js is called a module.
Now let's say you want to include a module, here comes require, you have used it right.
But since your module doesn't export anything, it's useless when it's included in some other module.
So at the end of your b.js file, add the following line :
module.exports.something = something;
Now we can finally use our exported variable :
var b = require('./b.js');
console.log('Something is : ' + b.something);
Now I am sure the issue is because there is a d.ts file included which contains a module called "Shared", and a require statement which includes a variable of the same name if it is being used in a NodeJS environment.
// shared.d.ts
declare module Shared { ... }
// other_module.ts
/// <reference path="shared.d.ts"/>
if(require) { var Shared = require("shared"); }
export class Something {
public someVar = new Shared.SomethingElse("blah");
}
So when I compile other_module.ts (which is actually a lot of separate files), it tells me Shared is a duplicate identifier, which I can understand as TS thinks Shared is a module, but then is being told it is the return of require.
The problem here is that the output of modules need to be compatible with nodeJS's require system, so in this case when other_module is required it will be in its own scope and will not know about Shared.SomethingElse so the require is needed so the internal modules in other_module will be able to access the Shared library, but in the browser environment it would get Shared.SomethingElse via the global scope.
If I remove the reference then the file wont compile as it doesn't know about Shared, if I remove the require when the module is loaded into nodejs (var otherModule = require("other_module")) it will complain that it doesn't know about Shared. So is there a way to solve this?
First the error
Duplicate identifier because you have Shared in shared.d.ts + in other_module.ts.
FIX A, be all external
If you want to use amd / commonjs ie. external modules, you need to use import/require (not var/require like you are doing). Using an import creates a new variable declaration space and therefore you are no longer polluting the global namespace Shared from other_module.ts. In short :
// shared.d.ts
declare module Shared {
export function SomethingElse(arg:string):any;
}
declare module 'shared'{
export = Shared;
}
And a typesafe import:
// other_module.ts
/// <reference path="shared.d.ts"/>
import Shared = require("shared");
export class Something {
public someVar = new Shared.SomethingElse("blah");
}
FIX B, as you were, but you need to use a different name then
Inside other_module don't use the name Shared locally if local scope is global scope. I recommend you just use external everywhere and compile for node with commonjs and browser with amd as shown in fix A, but if you must here is a compile fixed other_module.ts.
// other_module.ts
/// <reference path="shared.d.ts"/>
var fooShared: typeof Shared;
if(require) { fooShared = require("shared"); }
else { fooShared = Shared; }
export class Something {
public someVar = new fooShared.SomethingElse("blah");
}