RequireJS bundles load timeout - requirejs

I'm getting a load timeout from some of my modules when using bundles. The complete bundled source contains the script for the modules, but the timeout occurs anyway. Other modules in the bundle don't cause a timeout error.
Any bright ideas? The error is
Uncaught Error: Load timeout for modules:
system/mvc/collection,system/mvc/router,system/mvc/view
My configuration looks like this:
requirejs.config({
"baseUrl" : "/UIAssets/js/",
"paths" : {
"{0}" : "pc/0.6.5210.18633/fr"
},
"bundles" : {
"http://mydomain.com/0.6.5210.18633.combo?/UIAssets/js/system/mvc/model.js&/UIAssets/js/system/mvc/collection.js&/UIAssets/js/system/mvc/router.js&/UIAssets/js/system/mvc/view.js&/UIAssets/js/UI/views/Home.js&/UIAssets/js/pc/0.6.5210.18633/fr/Templates/shared/myPartial.js&/UIAssets/js/pc/0.6.5210.18633/fr/Templates/shared/copyright.js" : [
"system/mvc/router",
"system/mvc/model",
"system/mvc/collection",
"{0}/Routes",
"{0}/Resources/Routes",
"system/mvc/view",
"system/helpers/stringify",
"system/helpers/format",
"UI/views/Home",
"{0}/Templates/shared/myPartial",
"{0}/Templates/shared/copyright"]
}
});

Start with a high tolerance margin to see if it fixes the issue
requirejs.config({
waitSeconds: 16,
...
});
If it doesn't, then something's broken inside the bundle.

I experienced the same timeout issue, without any script errors. The reason turned out to be requiring the same script in two different ways in the same code base (but not the same file):
var somemodule = require('somemodule');
and
var somemodule = require('js/somemodule.js')
while I had the path configured like this:
require.config({
...
"paths" : {
"somemodule" : "js/somemodule.js"
},
...
});
So I had two copies of the same code being used, which somehow messed things up. Possibly some state was set in both copies separately?

Related

How to import a node module inside an angular web worker?

I try to import a node module inside an Angular 8 web worker, but get an compile error 'Cannot find module'. Anyone know how to solve this?
I created a new worker inside my electron project with ng generate web-worker app, like described in the above mentioned ng documentation.
All works fine until i add some import like path or fs-extra e.g.:
/// <reference lib="webworker" />
import * as path from 'path';
addEventListener('message', ({ data }) => {
console.log(path.resolve('/'))
const response = `worker response to ${data}`;
postMessage(response);
});
This import works fine in any other ts component but inside the web worker i get a compile error with this message e.g.
Error: app/app.worker.ts:3:23 - error TS2307: Cannot find module 'path'.
How can i fix this? Maybe i need some additional parameter in the generated tsconfig.worker.json?
To reproduce the error, run:
$ git clone https://github.com/hoefling/stackoverflow-57774039
$ cd stackoverflow-57774039
$ yarn build
Or check out the project's build log on Travis.
Note:
1) I only found this as a similar problem, but the answer handles only custom modules.
2) I tested the same import with a minimal electron seed which uses web workers and it worked, but this example uses plain java script without angular.
1. TypeScript error
As you've noticed the first error is a TypeScript error. Looking at the tsconfig.worker.json I've found that it sets types to an empty array:
{
"compilerOptions": {
"types": [],
// ...
}
// ...
}
Specifying types turns off the automatic inclusion of #types packages. Which is a problem in this case because path has its type definitions in #types/node.
So let's fix that by explicitly adding node to the types array:
{
"compilerOptions": {
"types": [
"node"
],
// ...
}
// ...
}
This fixes the TypeScript error, however trying to build again we're greeted with a very similar error. This time from Webpack directly.
2. Webpack error
ERROR in ./src/app/app.worker.ts (./node_modules/worker-plugin/dist/loader.js!./src/app/app.worker.ts)
Module build failed (from ./node_modules/worker-plugin/dist/loader.js):
ModuleNotFoundError: Module not found: Error: Can't resolve 'path' in './src/app'
To figure this one out we need to dig quite a lot deeper...
Why it works everywhere else
First it's important to understand why importing path works in all the other modules. Webpack has the concept of targets (web, node, etc). Webpack uses this target to decide which default options and plugins to use.
Ordinarily the target of a Angular application using #angular-devkit/build-angular:browser would be web. However in your case, the postinstall:electron script actually patches node_modules to change that:
postinstall.js (parts omitted for brevity)
const f_angular = 'node_modules/#angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js';
fs.readFile(f_angular, 'utf8', function (err, data) {
var result = data.replace(/target: "electron-renderer",/g, '');
var result = result.replace(/target: "web",/g, '');
var result = result.replace(/return \{/g, 'return {target: "electron-renderer",');
fs.writeFile(f_angular, result, 'utf8');
});
The target electron-renderer is treated by Webpack similarily to node. Especially interesting for us: It adds the NodeTargetPlugin by default.
What does that plugin do, you wonder? It adds all known built in Node.js modules as externals. When building the application, Webpack will not attempt to bundle externals. Instead they are resolved using require at runtime. This is what makes importing path work, even though it's not installed as a module known to Webpack.
Why it doesn't work for the worker
The worker is compiled separately using the WorkerPlugin. In their documentation they state:
By default, WorkerPlugin doesn't run any of your configured Webpack plugins when bundling worker code - this avoids running things like html-webpack-plugin twice. For cases where it's necessary to apply a plugin to Worker code, use the plugins option.
Looking at the usage of WorkerPlugin deep within #angular-devkit we see the following:
#angular-devkit/src/angular-cli-files/models/webpack-configs/worker.js (simplified)
new WorkerPlugin({
globalObject: false,
plugins: [
getTypescriptWorkerPlugin(wco, workerTsConfigPath)
],
})
As we can see it uses the plugins option, but only for a single plugin which is responsible for the TypeScript compilation. This way the default plugins, configured by Webpack, including NodeTargetPlugin get lost and are not used for the worker.
Solution
To fix this we have to modify the Webpack config. And to do that we'll use #angular-builders/custom-webpack. Go ahead and install that package.
Next, open angular.json and update projects > angular-electron > architect > build:
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
}
// existing options
}
}
Repeat the same for serve.
Now, create extra-webpack.config.js in the same directory as angular.json:
const WorkerPlugin = require('worker-plugin');
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
module.exports = (config, options) => {
let workerPlugin = config.plugins.find(p => p instanceof WorkerPlugin);
if (workerPlugin) {
workerPlugin.options.plugins.push(new NodeTargetPlugin());
}
return config;
};
The file exports a function which will be called by #angular-builders/custom-webpack with the existing Webpack config object. We can then search all plugins for an instance of the WorkerPlugin and patch its options adding the NodeTargetPlugin.

Typescript2 path module resolution

tl;dr : module resolution does not apply ?
Hello,
I am playing around with Typescript2 module resolution feature.
I've noticed that it is now possible to specify "Paths", so that you can do the following :
Old way
import {a} from "../../../foo"
New way
import {a} from "services/foo"
To do so, you need to add some configs to your tsconfig.json
"compilerOptions": {
"baseUrl": ".",
"paths": {
"services/*": ["./application/core/services/*"],
}
}
Problem that I have, is that when compiled, the import actually doesn't change. My javascript output still contains that import from "services/foo", so that obviously crash at runtime on my node server.
I use gulp-typescript to compile my javascript files :
var tsProject = ts.createProject("tsconfig.json");
return tsProject.src()
.pipe(sourcemaps.init())
.pipe(tsProject()).js
.pipe(sourcemaps.write("../api"))
.pipe(gulp.dest(function(file) {
return file.base;
}));
I am completely lost here and would love to use that module resolution, so that I can move away from that ../../ hell of imports. Any help would be more than appreciated !
The problem here is that the JavaScript Engine knows nothing about your TypeScript config, what you specify in your tsconfig is only used "compile time", when you have compiled your TypeScript into JS you need to do the same job as the TS compiler did but to save the resolved path in the JS file.
Simply put, all JS files needs to be processed and the aliases replaced with "real" paths.
Tip: Use the npm tool tspath (https://www.npmjs.com/package/tspath), it requires 0 configuration, just run it in somewhere in your project and all JS files will be processed and ready to run!

Requirejs paths getting overwritten intermittently

I have configured paths for handlebars and underscore in Requirejs config like so:
require.config({
baseUrl: '/js/',
paths: {
/* Core Libraries */
underscore : 'libs/underscore/underscore-min',
backbone : 'libs/backbone/backbone-min',
handlebars: 'libs/handlebars/handlebars.min'
}
This is how I initialize requirejs:
<script type="text/javascript" data-main="/js/main" src="/js/libs/require/require.js"></script>
When i refresh the page multiple times, I get an error message saying:
Uncaught Error: Script error for "handlebars".
Digging a little deeper, I could see in the network tab of Chrome Dev tools that it's basically a 404 not found for the modules:
404 Not Found - http://localhost:8888/js/underscore.js
The above path is not the one configured in require.config.
I'm not able to exactly pinpoint the issue as this occurs only intermittently.
Any help is much appreciated.
Thank you.
Backbone.js needs underscore.js so if you refresh the page multiple times the libraries may not be loaded with the correct order
Please try shim configuration as below;
require.config({
baseUrl:'js',
paths: {
/* Core Libraries */
underscore : 'libs/underscore/underscore-min',
backbone : 'libs/backbone/backbone-min',
handlebars: 'libs/handlebars/handlebars.min'
},
shim:{
'backbone': {
deps: ['underscore']
}
}
}

Getting 'Uncaught Error: Script error' for a declared dependency when using r.js

I couldn't find an answer for my issue on SO or Github, so I am posting this:
I created a repo for this issue:
https://github.com/saviomuc/requireJSMultiPage
I tried to set up require.js for a multipage project.
All is fine when I am running the page.
But when I try to optimize the files with r.js I am getting this error:
GET http://localhost:63342/requirejs/www-build/js/library.js 404 (Not Found) require.js:7
Uncaught Error: Script error for: library
http://requirejs.org/docs/errors.html#scripterror
The setup is like this:
js/app/app1.js
js/app/app1jq.js
js/lib/require.js
js/lib/library.js
main-page1.js
Currently require.js loads a file (main-page1.js) which contains this code
require(['common','app/app1','app/app1jq'], function (config) {});
common.js contains
requirejs.config({
paths: {
library: 'lib/library'
}
});
console.log('This is the config!');
app1jq.js contains
define(function (require) {
var library = require('library');
console.log('This is dependent on library');
});
Could this be an issue with the optimizer? Or did I do something wrong?
Best and thank you in advance!
The problem is that common is not guaranteed to be loaded first. So when RequireJS gets to require('library') then the configuration may or may not have been set. When you call require(['a', 'b', 'c'], function () {}) RequireJS is free to load c first, or b first, or a first. The order is not set. The only guarantee is that all the modules will be loaded before the callback is called.
So change main-page1.js so that it contains:
require(['common'], function () {
require(['app/app1','app/app1jq']);
});
This will ensure that common is loaded before any of the code that depends on your configuration.

Load timeout for modules while including a module with dependency

I am getting an error:
"Error: Load timeout for modules"
While trying to include a module with dependencies.
Am I doing this incorrectly?
My bootstrap:
requirejs.config({
baseUrl: "js",
paths: {
JqueryUiLatest: "jquery-ui-1.10.1.custom",
}
});
require([
'modules/outlookPopupModule'
], function(OutlookPopupModule){
...
});
My module:
define([
'jquery',
"JqueryUiLatest"
], function ($, JqueryUI) {
it seems to work if I replace "JqueryUiLatest" with the actual file "jquery-ui-1.10.1.custom" in the module, but this seems to defeat the purpose of being able to use the config.
I'm sure I'm doing something wrong here?
By my experience requirejs often fails with timeout when shim dependency module is a plain JS script, not wrapped AMD module. The only solution I have now - load such files manually prior to requirejs or load them explicitly in require/define calls by full name (including .js extensions). In require/define no timeout occurs.

Resources