Webpack inter-library dependency as in requireJS.config.shim - javascript

I am converting a grunt + requireJS build process to webpack. We have something like this:
require.config({
shim:{
'popover': {
deps: ['tooltip']
},
'tooltip': {
deps: ['jquery']
}
}
})
Where we are specifically saying that tooltip depends on jquery so load jquery first. Popover depends on tooltip so load tooltip beforehand.
How do I translate this configuration into webpack 4 ? I've searched through the web trying to see if there are anything similar enough. Webpack's shimming doesn't do inter-library dependency. I don't see anything in the documentation too ...which surprised me much.
I have find articles (https://gist.github.com/xjamundx/b1c800e9282e16a6a18e)
that suggest of use import-loader to achieve such effect. So my config is like this:
module:{
strictExportPresence:true,
rules:[
{ parser: { requireEnsure: false } },
{ oneOf:[...bunch of stuffs for different file types] },
{ test : /tooltip/, loader: 'imports-loader?$=jquery' },
{ test : /popover/, loader: 'imports-loader?tooltip' }
]
also have the appropriate aliases in config set up.
the error I am getting it the browser is Constructor undefined on line
"Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype ..."
so tooltip library isn't being loaded before popover is.
I also don't see any new code added by webpack, which I think this could be my first problem since imports-loader supposedly add the specified library into popover module right ?
I am exactly seeing what's wrong with my approach anymore and exhausted a lot of resources online. I am sure someone had to deal with this type of problem before, please shade some light for me. Thanks!

You should provide tooltip and popover in resolve.alias section:
resolve: {
alias: {
"jquery": "lib/jquery-x.x.x",
"tooltip": "lib/tooltip-x.x.x",
"popover": "lib/popover-x.x.x"
}
}
Otherwise webpack won't be able to resolve modules to shim by imports-loader. Also, please note that you misspelled imports-loader in your configuration.

Related

Mock library with webpack

I'm attempting to replace a library for testing.
The code I want to change:
import foo from 'foo-lib'; // foo-lib is a library dependency in package.json
I want this to import src/mock-foo.js instead.
This is for end-to-end tests, so I can't use something like Jest mocks.
I have a development-only webpack.config. In that I've tried:
resolve: {
alias: {
'foo-lib': path.resolve(__dirname, 'src/mock-foo.js')
},
extensions: ['.js'], // need this for some other aliases (not shown)
},
I've also tried the older technique in the plugins array:
new webpack.NormalModuleReplacementPlugin(
/foo-lib/,
'mock-foo.js'
),
as well as several variations on these.
I don't get errors, but the original library loads every time.
Is this even possible? If so, what's the correct syntax?
I think I've found one solution based on Replacing/aliasing a file using Webpack .
Testing with the is-number library (just for a simple example), this works:
plugins: [
new webpack.NormalModuleReplacementPlugin(
/is-number/,
require.resolve('./src/mock.js')
),
],
As one of the commenters on the other post mentioned, it's not clear why the resolve.alias approach didn't work.

How to set up plotly.js in nuxt SSR?

I'm trying to set up plotly.js in nuxt but whatever I do I get this cryptic error
self is not defined
I tried to install plotly.js and plotly.js-dist same error shows.
I would prefer to make custom build so I tried like this in nuxt plugins:
// here we use custom partial bundle
import plotly from 'plotly.js/lib/core';
import barpolar from 'plotly.js/lib/barpolar';
export default function (_, inject) {
plotly.register([barpolar]);
inject('plotly', plotly);
}
but whenever I register nuxt plugin site crashes with aforementioned error.
Even not going down custom bundle route, and using dist lib still fails just the same.
I also tried not to employ nuxt plugins system but to import manually and to set up, same things happen.
I also added ify-loader as recommended here: https://github.com/plotly/plotly-webpack
and this is my nuxt.config.js in regards to webpack plugin:
build: {
extend(config, { isClient }) {
console.log('config :>> ', config);
config.module.rules.push({
test: /\.js$/,
use: [
'ify-loader',
'transform-loader?plotly.js/tasks/compress_attributes.js',
],
});
},
},
still no luck.
I presume this is problem with webpack 5 and plotly.js not working well together in default setup but I have no idea how to solve this.
Help appreciated.
The reason why this wasn't working is that plotly tried to access document, and in SSR that would obviously fail.
So to fix this I just had to assign plugin in client only mode like this:
plugins: [
// other plugins
{ src: '~/plugins/plotly', mode: 'client' },
],
and it worked.

Using webpack to process an AMD library with external dependencies

I have a library written in AMD style that can be used with RequireJS. jquery and jquery-ui are assumed to be provided by the user of the library. Say it looks like this:
// main-lib.js
define(['jquery', './aux-lib.js'], function ($) { ..(1).. });
// aux-lib.js
define(['jquery', 'jquery-ui'], function ($) { ..(2).. });
I'm trying to figure out how webpack works. For example, say I want to bundle these files into a single AMD style library file that still assumes jquery and jquery-ui from the outside:
// out.js
define(['jquery', 'jquery-ui'], function ($) { ..(1)..(2).. } );
How is this accomplished?
When I run webpack with main-lib.js as entry-point, it will complain that it can't find jquery and jquery-ui. If I configure the correct paths with resolve.alias, it bundles jquery and jquery-ui into out.js, which is not what I want. I tried using output.externals to no avail.
This was a pretty simple, stupid mistake on my part. The relevant field is not output.externals, but simply externals. See here. The other two relevant fields introduced there are inside output, but externals is not.
PS: externals can also be an array. Here is my current configuration:
{
entry: './main-lib.js',
output: {
path: './',
filename: 'out.js',
libraryTarget: 'amd'
},
externals: ['jquery', 'jquery-ui']
}
It's working quite nicely.

Using OpenLayers with RequireJS and AngularJS

I'm trying to get an app running that uses both AngularJS and RequireJS. I'm having problems getting my OpenLayers lib to work in this setup.
I set the main AMD-modules in the main.js:
require.config(
{
baseUrl: 'scripts',
paths: {
// Vendor modules
angular: 'vendor/angular/angular',
openLayers: 'vendor/openlayers-debug',
other modules.....
},
shim: {
angular: {
exports: 'angular'
},
openLayers: {
exports: 'OpenLayers'
},
other modules....
}
}
);
require(['openLayers',
'angular',
'app',
'controllers/olMapController',
'directives/olMap',
other modules...
], function(OpenLayers) {
return OpenLayers;
}
);
Then in the angular controller I use for the initialisation of OpenLayers, I try to indicate that openlayers-debug.js is a dependency:
define(['openLayers'],
function(OpenLayers) {
controllers.controller('olMapController', ['$scope', function(scope) {
console.log('Loaded olMapController. OpenLayers version: ' + OpenLayers.VERSION_NUMBER);
}]);
}
);
Well, this doesn't work. SOMETIMES the olMapController function is executed, but mostly not. The console then just displays an error stating:
Error: [ng:areq] Argument 'olMapController' is not a function, got undefined
So, I think OpenLayers hasn't finished loading yet, but somehow require thinks it has and continues loading code that depends on OpenLayers, in this case the olMapController. It then can't find its dependency, whereupon Angular returns this error message. Or something like that...? Sometimes something happens that makes OpenLayers load fast enought for it to be present when it is loaded as a dependency. What that is, I can't tell.
I left out other libraries and modules require and define to keep the code readable. I hope the example is still understandable.
Any ideas on what I could do to get openlayers to load well? The error message disappears when I leave the ['openLayers'] dependency out of olMapController.
Thanks in advance for any help.
Best regards,
Martijn Senden
Well, just for reference my final solution. The comment by angabriel set me off in the right direction.
Like i said, I'm using the domReady module provided by RequireJS to bootstrap Angular. This is still being called to early, because OpenLayers isn't loaded yet when angular starts. RequireJS also provides a callback property in require.config. This is a function that is triggered when all the dependencies are loaded. So I used that function to require the angular bootstrap module. My config now looks like this:
require.config(
{
baseUrl: 'scripts',
paths: {
// Vendor modules
angular: 'vendor/angular/angular',
domReady: 'vendor/domReady',
openLayers: 'vendor/openlayers-debug',
etcetera....
},
shim: {
angular: {
deps: ['jquery'],
exports: 'angular'
},
openLayers: {
exports: 'OpenLayers'
},
},
deps: ['angular',
'openLayers',
'app',
'domReady',
'controllers/rootController',
'controllers/olMapController',
'directives/olMap'
],
callback: function() {
require(['bootstrap']);
}
}
);
And the bootstrap module looks like this:
define(['angular', 'domReady', 'app'], function(angular, domReady) {
domReady(function() {
angular.bootstrap(document, ['GRVP']);
});
});
Thanks for the help. #angabriel: I upvoted your comment. It's not possible to accept a comment as an answer, is it? Your initial answer wasn't really the answer to my question, but the comment helped a lot...
Regards, Martijn
Sorry this answer will only contain text as your code is too big for a small example.
I would suggest to write a directive that utilizes head.js to load libraries you need at a specific context. One could also think of a directive that initializes openLayers this way.
I guess your error is a timing problem, because the require.js and angular.js module loading gets out of sync - more precisely there seems to be no sync at all between them.
update
To repeat my comment which lastly helped to lead the OP in the right direction:
You have to decide which framework gives the tone. If you go with requireJS, then require everything and bootstrap angular manually. (Remove ng-app="" from index.html) and do `angular.bootstrap()ยด when requirejs has completed. So the problem most likely is, that angular starts too early.

Getting dependencies to load correctly in requirejs (autobahn and whenjs)

I have been stuck on this problem for the past few hours. I'm trying to get autobahnjs and whenjs to be loaded correctly by requirejs.
require.config({
paths: {
angular: '../bower_components/angular/angular',
angularBootstrap: '../bower_components/angular-bootstrap/ui-bootstrap',
bootstrap: '../bower_components/bootstrap/dist/js/bootstrap',
jquery: '../bower_components/jquery/jquery',
chosen: '../bower_components/chosen/chosen.jquery.min',
text: '../bower_components/requirejs-text/text',
autobahn: '../bower_components/autobahnjs/autobahn/autobahn'
},
packages: [
{ name: 'when', location: '../bower_components/when/', main: 'when' }
],
baseUrl: '/bundles/example/app/scripts/',
shim: {
angular : {
exports : 'angular'
},
angularBootstrap: {
deps: ['angular']
},
autobahn: {
deps: ['when']
}
},
priority: [
'angular'
]
});
require
( [
'angular',
'app',
'autobahn',
'angularBootstrap',
'jquery',
'bootstrap',
'chosen',
'controllers/event',
'services/notify'
], function(angular, app) {
// more code here
});
Autobahnjs has a dependency on whenjs. All the files are loaded (and in the correct order). but when is always undefined. I have absolutely no idea what I'm doing wrong. I've tried all sorts of ways to solve it. I also have a bower.json file if this helps anyone replicate the problem. Thanks in advance.
EDIT: Autobahnjs does not currently support AMD. Whenjs, however, does support it.
As you have noticed already, there is an issue for adding requirejs support to AutobahnJS. There is also more embedded stuff inside AutobahnJS bundled for "convenience", mainly parts from cryptojs.
The challenge simply is: how to best serve all users, not matter if and what module loader they use, and if they want convenience (bundled stuff) or prefer to have stuff separate (and manage/load that themselves).
I can't promise, but I try to address it with priority. However, for further discussion, I think the best place would be the GitHub issue.
This has now been implemented in v0.8.0

Categories

Resources