Angular2 + Webpack DefinePlugin not working? - node.js

I tried to run the Angular2 app from the tutorial on the angular.io website
Angular2 with Webpack Tutorial on angular.io
Installation worked well (with a few hiccups, it's Ubuntu 14.04 LTS) but I got to the point where the npm start task works, the server works, and even the app works in the browser, so far so good. But
Everytime I run npm start, I get the following 2 errors in the terminal, AND in the browser console:
ERROR in ./src/polyfills.ts
(4,5): error TS2304: Cannot find name 'process'.
ERROR in ./src/main.ts
(7,5): error TS2304: Cannot find name 'process'.
If you look at the tutorial, it is explained how to create the webpack configs, there is a webpack.common.js, a webpack.prod.js and a webpack.dev.js. In the webpack.prod.js, a var is created with this code:
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
new webpack.DefinePlugin({
'process.env': {
'ENV': JSON.stringify(ENV)
}
})
In main.ts and in polyfills.ts the var is referenced by this:
if (process.env.ENV === 'production') {
enableProdMode();
}
but it seems, that Typings does not know how to inject these variables, created with webpack.DefinePlugin into the compiled Javascript (that's what I'm thinking, I maybe wrong)
If anyone ran into the same problem, or anyone can help me with this, I would be very thankful! (All the code is from the tutorial, so anyone who tried the tutorial may have run into the same problem, I guess?!)
Thank You!

I was having the same issue here (doing the same tutorial). To solve this I created a file named typings.d.ts on the same folder where typings.json is (this file will be included by default by the compiler) and added the following declaration to it:
declare var process: any;
Hope it helps! :)

Related

"TypeError: Cannot read property 'indexOf' of undefined" raised when using packages "onoff" or "rpi-gpio" with WebPack

I wrote a Node.JS project for the Raspberry PI, to control the GPIO.
This is my first time using GPIO.
The project uses the "onoff" package to communicate with GPIO. And the compiler is WebPack.
I can compile the project without issue.
But when I run the application on the RaspberryPI, I receive this error:
webpack:///./node_modules/bindings/bindings.js?:178
if (fileName.indexOf(fileSchema) === 0) {
^
TypeError: Cannot read property 'indexOf' of undefined
at Function.getFileName (webpack:///./node_modules/bindings/bindings.js?:178:16)
at bindings (webpack:///./node_modules/bindings/bindings.js?:82:48)
at eval (webpack:///./node_modules/epoll/epoll.js?:7:86)
at eval (webpack:///./node_modules/epoll/epoll.js?:15:3)
at Object../node_modules/epoll/epoll.js (/home/pi/xilium/raspi.node/Raspi.node/dist/raspi.multi-monitor.js:809:1)
at __webpack_require__ (/home/pi/xilium/raspi.node/Raspi.node/dist/raspi.multi-monitor.js:20:30)
at eval (webpack:///./node_modules/rpi-gpio/rpi-gpio.js?:6:20)
at Object../node_modules/rpi-gpio/rpi-gpio.js (/home/pi/xilium/raspi.node/Raspi.node/dist/raspi.multi-monitor.js:1375:1)
at __webpack_require__ (/home/pi/xilium/raspi.node/Raspi.node/dist/raspi.multi-monitor.js:20:30)
at eval (webpack:///./src/raspi.multi-monitor.ts?:29:15)
So, I tried replacing the "onoff" package with "rpi-gpio". Unfortunately, the result is the same.
It seems that there is a configuration issue for "epoll" package (a dependence of "onoff" and "rpi-gpio").
Can anyone help me?
As a disclaimer, I am new to electron, webpack and everything around it, but after a lot of searching, I finally managed to get it working. I am not sure if this is the proper way to do it yet, but I just got it to work.
While searching far and wide, I found this comment on an issue from the serialport package, where they use electron-rebuild to rebuild the serialport module. More info about using native node modules can be found in the Electron documentation here.
Basically, I this to the scripts of my package.json:
"rebuild": "electron-rebuild -f -w onoff"
Then I ran npm run rebuild. Unfortunately, it still didn't work.
What was the missing link, was to tell webpack that the onoff module should be external.
I did it like so, in the webpack config that builds the electron parts of my app (setup is based on this guide I read):
'use strict';
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: './src/electron/main.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'out/electron')
},
module: {
rules: []
},
resolve: {
extensions: ['.js']
},
plugins: [
// This is the important part for onoff to work
new webpack.ExternalsPlugin('commonjs', [
'onoff'
])
],
// tell webpack that we're building for electron
target: 'electron-main',
node: {
// tell webpack that we actually want a working __dirname value
// (ref: https://webpack.js.org/configuration/node/#node-__dirname)
__dirname: false
}
};
As I wrote this, I stumbled upon externals config that might just work the same as well.
Now, finally I can blink my LEDs. I hope this answer can help anyone else in the future that might have the same issue.

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 : 'child process'

I'm developing a ReactJS app with Babel and Webpack. I am using the create-react-app facebook script so it handles the Webpack´s configuration. My problem is that I created a js file and add:
var childProcess = require('child_process');
But when I want to compile the new version i get the following error :
Module not found: 'child_process'.
I don't know what to do with this . I have read that adding custom configurations to the webpack.config.js may be the solution but i am using create react app so I don't have the Webpack configuration. I tried running npm run eject and create my own webpack.config.js but it doesn't work.
I hope somebody could help me.
You need to configure the correct target inside the webpack configuration: https://webpack.github.io/docs/configuration.html#target
module.exports = {
entry: './path/to/my/entry/file.js',
...
target: 'node',// we can use node.js modules after adding this configuration
};

How to update express/lib/application.js to match different app.js file?

MEAN noob here. I was following this tutorial, but npm start gives me the following error:
Error: Cannot find module './view'...
at Object.<anonymous> (C:\root\node_modules\express\lib\application.js:22:12)
This is what application.js says at that location:
var query = require('./middleware/query');
var debug = require('debug')('express:application');
var View = require('./view'); /////// line 22
I have a lib/middleware but not a lib/view, nor lib/util...
My theory is perhaps I screwed the express installation up: It's possible I didn't have the correct app.js in place when I installed it. Does app.js affect express's installation?
Is there a way to rebuild express or express/lib without uninstalling & reinstalling everything?
Would this even fix my problem?

Deploy React.js Starter Kit on Openshift

I'm trying to deploy the Starter Kit of React.js (available here : https://github.com/kriasoft/react-starter-kit) on Openshift. To do that, I modified some little things that I explain here.
First, the logs in Openshift tells me that the import keyword in the servers.js file is not recognized. I think Babel is not used by Openshift at this point.
A workaround for that is mentioned here : How do I modify the node startup command in Open Shift?
So I modified the server.js content (because Openshift run the node server.js command and not the babel-node tools/run start defined in the scripts.start property of package.json) with the recommended content and renamed my base server.js to app.js.
Now, the logs tells me that babel-core is not found so I modified the package.json file to put babel-core and babel-cli in dependencies instead of devDependencies and remove a DEV value of another property.
All the times, when I push my code on Openshift (code of the src folder), the compilation failed at a random time (when dependencies are installed) and it take a long long time. However, when I reboot the cartridge I can see logs I explained.
My current situation is that things are looking better but the problem is the disk space : not enough. That's surprising me because the cartridge can host 1GB and on my local machine all files with dependencies take ~148MB. I tried to delete and recreate the cartridge : the same thing appears.
Does anybody know what can be wrong here ? The fact that the cardridge exceed 1GB is weird...
Thank you all.
Here's the solution... I hope it will save hours for some people !
Set the "production" mode to the cartridge app (so that in don't download so many inodes) :
rhc set-env NODE_ENV=production --app appname
Don't forget to modify config.js :
export const port = process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 3000;
export const host = process.env.OPENSHIFT_NODEJS_IP || 'localhost';
export const databaseUrl = 'sqlite:' + process.env.OPENSHIFT_DATA_DIR + 'database.sqlite';
Modify app.js (include the host):
import { port, host, auth, analytics } from './config';
//...
models.sync().catch(err => console.error(err.stack)).then(() => {
app.listen(port, host, () => {
console.log(`The server is running at http://${host}:${port}/`);
});

Resources