How can I confgure webpack to ignore amd 'define' statements in the file, like I can do it with 'require' with externals option?
as stated here: https://github.com/webpack/webpack/issues/3017#issuecomment-285954512
you could do:
module: {
rules: [
{ parser: { amd: false } }
]
}
Officially it is recommended to set define to false with imports-loader.
loaders: [
{ test: /\.js/, loader: 'imports?define=>false'}
]
But it is useful only if define is called in UMD style - something like this:
if (typeof define === 'function' && define.amd) {
define([], factory)
}
If you can change code that calls define and there is no UMD's if this is what worked for me:
var define = window['infor']; // keep webpack out of way
// use define from global scope (requirejs or other used loader) as needed
define('mymodule', ['dep1'], function (dep1) {
return {}
});
Related
I currently write a d3 plugin. However, I want to call this plugin as property of the global d3 as in the original example:
d3.foo()
But when I do this, my configurations for rollup lead to a clash of the d3 references.
Here is one minimal example (with just one file) to illustrate:
I downloaded the original example of the d3 plugin and slightly changed the source file foo.js:
//.src/foo.js
import * as d3 from "d3";
export default function() {
return d3.select("body").append("div").text(42);
};
So here is my plugin. It uses d3 functions (d3.select()) therefor d3 is imported at the top.
My index.js looks like this:
export {default as foo} from "./src/foo";
So I export the function foo().
My rollup.config.js looks like this:
//rollup.config.js
import babel from "rollup-plugin-babel";
var globals = {
"d3": "d3",
};
export default {
entry: "index.js",
dest: "build/d3-foo.js",
format: "umd",
moduleName: "d3",
external: Object.keys(globals),
globals: globals,
plugins: [
babel({
exclude: "node_modules/**"})
]
};
I have set moduleName to "d3" since I want to call my plugin as d3.foo(). I also set the globals and external to "d3" since I don't want the d3 modules to be bundled by rollup.
To call my d3 plugin I use the following html code:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.js"></script>
<script src="./build/d3-foo.js"></script>
</head>
<body>
<script>
d3.foo();
</script>
</body>
</html>
But this does not work since the d3 namespace is refering to the d3 library which does not contain a function called d3.foo().
The generated bundle looks like this:
// build/d3-foo.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3'], factory) :
(factory((global.d3 = {}),global.d3));
}(this, (function (exports,d3) { 'use strict';
function foo () {
return d3.select("body").append("div").text(42);
}
exports.foo = foo;
Object.defineProperty(exports, '__esModule', { value: true });
})));
If instead I call the moduleName in rollup.config.js any other name (e.g. d4) I can call the plugin with d4.foo() and it works.
How do need to adjust the rollup config file to be able name my plugin d3.foo as suggested by mike bostock in his blog?
Any help would be greatly appreciated!
I found a solution how the desired final bundle should look like, thanks to Mike Bostock.
The rollup.config.js can be specified as follows:
// rollup.config.js
import babel from "rollup-plugin-babel";
import * as meta from "./package.json";
export default {
input: "index.js",
external: ["d3"],
output: {
file: `build/${meta.name}.js`,
name: "d3",
format: "umd",
indent: false,
extend: true,
// banner: `// ${meta.homepage} v${meta.version} Copyright ${(new Date).getFullYear()} ${meta.author}`,
globals: {d3: "d3"},
plugins: [
babel({
exclude: "node_modules/**"})
]
},
};
...resulting in the following bundle:
// build/d3-foo.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3'], factory) :
(factory((global.d3 = global.d3 || {}),global.d3));
}(this, (function (exports,d3) { 'use strict';
function foo() {
return d3.select("body").append("div").text(42);
}
exports.foo = foo;
Object.defineProperty(exports, '__esModule', { value: true });
})));
i have been reading this guide on react where the following paragraph has kind of thrown me.
For a number of good technical reasons CommonJS modules (i.e.
everything in npm) cannot be used natively in the browser. You need a
JavaScript “bundler” to “bundle” these modules into .js files that you
can include in your web page with a tag.
I was under the impression that i could do something like npm install jquery and then in my index.html file reference this through node modules, something like
<script src="node_modules/jquery/dist.jquery.js">
Is this not the case, or am I incorrect?
Yes. You are correct. Jquery is a global module not a commonjs module. For other package that use commonjs module, using import/export statement you need a bundler like browserify to bundle it into a single bundle in order to use it in browser
As mentioned in the guide you read, examples for those "bundlers" are webpack/browserify/systemjs/etc..
These are what is called as "module-loaders" which basically loads the modules to the browser when running your applications.
These module-loaders have a configuration file.
So if for example yours is webpack, after you install npm install webpack you'll need to have a webpack.config.js that might look as follows:
module.exports = {
entry: "./app/boot",
output: {
path: __dirname,
filename: "./dist/bundle.js"
},
resolve: {
extensions: ['', '.js', '.ts']
},
module: {
loaders: [
{ test: /\.ts/, loader: ["ts-loader"], exclude: /node_modules/ },
],
preLoaders: [
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ test: /\.js$/, loader: "source-map-loader", exclude: ['node_modules', 'ext-*', 'lib', 'tools'] }
]
},
debug: true,
devtool: 'source-map'
};
When the jquery library is loaded, it verifies if it is being imported by a bundler/loader or by a script tag:
( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global ); // export globally
}
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { /** jQuery definition **/ }
I need to write a module that will be available on the window global.
I'm using es6 to create the module and every single class I define has it's own file.
I'm using webpack to babelify and bundle these classes.
The entry point of my module is also the file containing the global to be exposed.
I've tried every method to make this possibe, icluding:
expose-loader
import-loader
expoert-loader
output: library
black-magic :(
Example of code I've tried:
I want to get: window.MyMod
// mymod.js
export class MyMod {
constructor(aaa) {
this.aaa = aaa;
}
toString() {
return this.aaa;
}
}
// webpack.config
var entries = [
'./src/mymod.js'
];
module.exports = {
...,
module: {
loaders: [
{
test: require.resolve('./src/mymod.js'),
loader: 'expose?MyMod'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
}
]
}
This only gets me an object MyMod on the window that contains MyMod as a constructor.
Any help will be appreciated.
You should combine export default class Foo with the library and libraryTarget settings in Webpack's config. Something like:
// src/Foo.js
export default class Foo { ... }
// webpack.config.json
{
"output": {
"library": "Foo",
"libraryTarget": "var"
}
}
You should be able to use the library as window.Foo once the bundle has been loaded.
This is basically the same issue as Exporting a class with Webpack and Babel not working , except that you have a named export instead of a default export. Your entry file should be
import {MyMod} from './mymod';
module.exports = MyMod;
or
module.exports = require('./mymod').MyMod;
If you don't want to do any of these and keep './src/mymod.js' as entry file, use a CommonJS export instead of an ES6 export in that file:
// mymod.js
exports.MyMod = class MyMod {
constructor(aaa) {
this.aaa = aaa;
}
toString() {
return this.aaa;
}
}
So i have this function. I am trying to get a new Test('selector', {}) from outside this js file, it comes undefined and i can't seem to figure out why.
Do i really need to attach it to the window object ?
Can someone explain this ?
TO mention it works from the same file.
let Test = ((window, document, undefined) => {
class test {
constructor(selector, options) {
this.selector = document.querySelector(selector);
this.options = options;
}
}
return test;
})(window, document);
This is my webpack config file:
module.exports = {
entry: './src/test.js',
module: {
loaders: [
{
test: /\.js?$/,
exclude: / (node_modules) /,
loader: 'babel-loader',
query: {
presets: ['es2015', 'stage-0']
}
}
]
},
output: {
path: __dirname + '/src',
filename: 'test.min.js'
}
}
I was clearly misunderstanding what webpack is doing. Webpack turns all your JavaScript files into modules that are not available in the global namespace. That's why we need to use require/import to load them in. In the above example the Test function was never loaded in and is not defined. The default scoping nature of JavaScript no longer exists.
In my (first) Webpack build I'm having trouble comprehending how I should be loading a script that simply exposes a global var.
The script I'm trying to load is basically something like this:
//File: MyLibrary.js
var MyLibrary = (function(window) {
function MyLibrary() {
// Do librarious stuff
}
return MyLibrary;
})(typeof window !== 'undefined' ? window : null);
I figured I should use the exports-loader since according to the docs it should be just the thing for this case:
The file sets a variable in the global context with var XModule = ....
var XModule = require("exports?XModule!./file.js")
So I put this in my config:
module: {
loaders: [
{
test: /MyLibrary\.js$/,
loader: "exports?MyLibrary!./MyLibrary.js"
}
]
}
But this results in an error:
ERROR in Loader MyLibrary.js didn't return a function
which confuses me, since it's not supposed to return a function, that's the whole point why I'm using this particular loader...
So how should I load the script?
you don't specify the path to the library in loader property, simply:
module: {
loaders: [
{
test: /MyLibrary\.js$/,
loader: "exports?MyLibrary"
}
]
}