Webpack'd oboe module will not run - node.js

I've compiled a project using webpack, which among its dependencies has oboe. After including the compiled project as a dependency in a node project, and starting it up with npm run dev, I get this error:
/usr/src/app/node_modules/#myproject/blockchain/lib/#myproject/blockchain.js:37762
return self;
^
ReferenceError: self is not defined
Looking at that bit of code in the compiled project, I find
// Access to the window object throws an exception in HTML5 web workers so
// point it to "self" if it runs in a web worker
try {
return window;
} catch (e) {
return self;
}
Seems like this is some kind of Webpack feature, but I'm not sure how to cope with it. I found this thread, but looking at my current configuration for globalObject:
globalObject: 'typeof self !== \'undefined\' ? self : this'
that does not seem to be the right answer. I looked through the output configuration of Webpack, but not sure what I'm looking for.
Any idea how I can include oboe as a dependency such that it will run in a webpack compiled project?

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.

Module not found error when trying to use a module as a local module

I am trying to understand as how to make a local module. At the root of node application, I have a directory named lib. Inside the lib directory I have a .js file which looks like:
var Test = function() {
return {
say : function() {
console.log('Good morning!');
}
}
}();
module.exports = Test;
I have modified my package.json with an entry of the path to the local module:
"dependencies": {
"chat-service": "^0.13.1",
"greet-module": "file:lib/Test"
}
Now, if I try to run a test script like:
var greet = require('greet-module');
console.log(greet.say());
it throws an error saying:
Error: Cannot find module 'greet-module'
What mistake am I making here?
modules.export is incorrect. It should be module.exports with an s.
Also, make sure after you add the dependency to do an npm install. This will copy the file over to your node_modules and make it available to the require function.
See here for a good reference.
Update:
After going through some examples to figure this out I noticed, most projects have the structure I laid out below. You should probably format your local modules to be their own standalone packages. With their own folders and package.json files specifying their dependencies and name. Then you can include it with npm install -S lib/test.
It worked for me once I did it, and it'll be a good structure moving forward. Cheers.
See here for the code.

Marionette Modules missing after minifying the files through grunt

I'm using Backbonejs with RequirejS to create an application and used
Grunt as a build tool. Minified files were generated using grunt task "grunt-requirejs".
After that I implemented MarionetteJs for using the marionette modules and after implementing marionette modules in the application, the problem started occurring in Grunt build process. When i'm running the application with minified file, i'm getting error
"uncaught Error: undefined missing modules/main/mainApp"
mainApp.js is my main module which would govern the other modules.
Code snippet
app.js -
define([ 'marionette' ], function(Marionette) {
var MainApplication = new Marionette.Application();
MainApplication.on("start", function(){
if(Backbone.history){
require(['modules/main/mainApp'], function (MainApp) {
Backbone.history.start();
MainApp.start();
});
}
});
return MainApplication;
}
I googled a lot about this question but couldn't find a concrete solution.
Do i have to include any other task for minifying the marionette files?
Also i came up with this blogpost , which confuses whether to used Requirejs with Marionette modules.
Any suggestions/approach for checking the marionette files are minified and are working correctly would be really helpful.
Edit:
Added code snippet.
I got the solution. It was just simply adding one more option to the optimization task.
In my grunt task
requirejs: {
compile: {
options: {
findNestedDependencies: true,
// Edited for brevity
}
}
},
I added findeNestedDependencies : true and it actually picked up the nested dependencies.
I got the reference from David Sulc's book for RequireJS, BackboneJS and Marionette. In this book he was optimizing the application with RequireJS optimizer and then i found that attribute in the build.js file.

'Cannot find module' error using karma-browserify on Windows

I'm attempting to set up unit testing on an Angular/Browserify project using Karma, Karma-Jasmine, and Karma-Browserify. I'm on a Windows machine, for reference. karma-cli is on my global npm path, and karma, karma-jasmine, karma-browserify, and browserify are all local npm installs, using -D.
I'm trying to pull in a single spec file, which looks like:
var PhoneListCtrl = require('../../../public/js/app/controllers/phone-list');
describe('PhoneListCtrl', function() {
var scope,
ctrl;
beforeEach(function() {
scope = {};
ctrl = new PhoneListCtrl(scope);
});
it('should create "phones" model with 3 phones', function() {
expect(scope).not.toBe(undefined);
});
});
And I get the following error every time:
Uncaught Error: Cannot find module 'Cc/gGH'
I get this exact same error after cloning the following repos, installing karma and all plugins, and attempting to run their example test suites:
https://github.com/xdissent/karma-browserify
https://github.com/waye929/angular-browserify
What on earth am I doing wrong? The test spec module is found correctly, and karma seems to be finding all necessary plugins/preprocessors, but it appears that karma-browserify is tripping on the require statement in a spec every time, for reasons I cannot fathom.
I've uninstalled and reinstalled karma and all related plugins numerous times now, to no avail.
I managed to find a solution. The issue was caused by karma-browserify's own module name hashing function, which is incompatible with newer versions of browserify. There's a fork that deals with it by using browserify's hashing function:
https://github.com/voidlock/karma-browserify/commit/3afe3b7485f2e4723bba5ad1c5a730d560b8c234
There's a pull request pending but in the meantime you can use the fork by placing
"karma-browserify": "https://github.com/voidlock/karma-browserify/tarball/use-browserify-hash-function"
in your package.json (dev)dependencies section.

ThreeNodes.js / NodeJS / CoffeeScript - Error During Build to Static JS

I ran server.js with node and everything worked perfectly. It's when I try to run the build script to create a compiled static version. I should also mention that it does output most of the files, but then throws an error mid-way.
I ran:
node server.js build
It seemed to work fine until it got to "Starting to Optimize the javascripts..."
Error Output:
/root/threenodes/ThreeNodes.js/node_modules/requirejs/bin/r.js:14153
throw new Error(errorMsg);
^
Error: TypeError: Object function () {
//A version of a require function that passes a moduleName
//value for items that may need to
//look up paths relative to the moduleName
var args = aps.call(arguments, 0), lastArg;
if (enableBuildCallback &&
isFunction((lastArg = args[args.length - 1]))) {
lastArg.__requireJsBuild = true;
}
args.push(relMap);
return func.apply(null, args);
} has no method 'nameToUrl'
In module tree:
threenodes/App
order
at Object.load (eval at <anonymous> (/root/threenodes/ThreeNodes.js/node_modules/requirejs/bin/r.js:13687:38))
I've just committed a fix to threenodes.js which should resolve your issue. It was caused by the fact that requirejs has been updated and the !order plugin is now deprecated. So the fix was simply to define a more precise version of requirejs in package.json.
https://github.com/idflood/ThreeNodes.js/commit/440757aa579ae3d35354e960a2bd5745bdee6847
To fix it:
git pull origin master
npm install -d
node server.js build
As a side note, the dev branch use the new version of requirejs. It's still not merged on master because I've started to work on "node grouping" but it is not finished yet. Apart from this all other functionality should work the same way as on the master branch. So if you plan to develop something on top of threenodes I would recommend to use the dev branch ; ]

Resources