I've just started using eslint. I initialized it and started fixing problems it pointed out.
One problem, however, it shouldn't complain about:
const data = fs.readFileSync(path.join(__dirname, _FILENAME));
The error is:
error '__dirname' is not defined
I did some searching and found that when you add --experimental to the node command that __dirname is not defined. This, however, isn't the case for me. I'm not running node with the --experimental flag.
See these questions:
Alternative for __dirname in Node.js when using ES6 modules
__dirname is not defined in nodejs
This is happening because ESLint does not know that your code is supposed to be used in Node.js: __dirname is not defined in browsers and also not defined in ES modules. To tell ESLint that your code will run in Node.js as a CommonJS module, open your ESLint config and set node: true in the env section. If you are using .eslintrc.json:
{
"env": {
"node": true
}
}
There are also other ways to specify environments, they are explained in the related documentation.
I ran into the same. Adding this to .eslintrc.json fixed it for me:
"globals": {
"__dirname": true
}
Got the idea from this similar question about the process global: https://stackoverflow.com/a/56777068/936907
Related
How could I add a script to my package.json file that would allow me to dynamically use a local file instead of a package version based on an environment variable?
"dependencies": {
"dynamic-dependency": "$(process.env.NODE_ENV !== 'dev' ? '^1.0.7' : 'file:../local-path-to-package')"
}
You can't do this in package.json, which is non-executable JSON file. The JSON variant used in package.json doesn't even support comments :). The purpose of package.json is to specify which dependencies are installed into node_modules, and that's it. With those dependencies installed, they can be used by Node at runtime, which locates them using the module resolution algorithm:
If the module identifier passed to require() is not a core module, and does not begin with '/', '../', or './', then Node.js starts at the parent directory of the current module, and adds /node_modules, and attempts to load the module from that location. Node.js will not append node_modules to a path already ending in node_modules.
So you can't use NPM/package.json for this. But, I see that you tagged your question with React, so if you are using Webpack, you can solve this issue in your Webpack config. This can be done with resolve.alias:
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
'dynamic-dependency': process.env.NODE_ENV !== 'dev' ? 'dynamic-dependency' : path.resolve(__dirname, '../local-path-to-package'),
},
},
};
I have not used other JS bundlers, but I would have to think Parcel/Rollup etc support this kind of configuration as well.
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.
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.
I am using Angular2/Typescript/Webpack to build an application
I'm having problem setting the Webpack option publicPath dynamically. In the official Webpack docs, it says:
Note: In cases when the eventual publicPath of output files isn't known at compile time, it can be left blank and set dynamically at runtime in the entry point file. If you don't know the publicPath while compiling you can omit it and set __webpack_public_path__ on your entry point.
My question: But how do I set this __webpack_public_path__ variable and where?
I thought I would have to set it in src/main.ts, but then I just get compiler error ERROR in ./src/main.ts
Cannot find name '__webpack_public_path__' when I build the project:
Isn't main.ts where I should set this variable? I even tried to set it in the built version of the file, main.js, and that didn't work either. Here is part of my Webpack config where I set the entry point.
config.entry = isTest ? {} : {
'polyfills': './src/polyfills.ts',
'vendor': './src/vendor.ts',
'app': './src/main.ts' // our angular app
};
compiler error ERROR in ./src/main.ts
TypeScript compiler errors are mostly just really powerful linting. More on this.
That compiler errors just tells you the TypeScript doesn't know about __webpack_public_path__. Just create globals.d.ts with :
declare var __webpack_public_path__:string;
And you should be golden. More on this 🌹
I'm writing some code for Node.js and I'm currently using JSHint to check over my code. However, when I use the require function to import modules, it says:
'require' is not defined.
How can I suppress the warning?
"use strict";
var express = require('express');
var register = require('./routes/register');
jshint is not aware of node.js globals by default you need to inform it.
add this comment to the top:
/* jshint node: true */
We can set node as the global environment variable in JSHint's .jshintrc file
This option defines globals available when your code is running inside of the Node runtime environment. Node.js is a server-side JavaScript environment that uses an asynchronous event-driven model. This option also skips some warnings that make sense in the browser environments but don't make sense in Node such as file-level use strict pragmas and console.log statements.
For more info http://jshint.com/docs/options/#node
{
"node": true
}
Errors like 'require' is not defined, 'console' is not defined, 'module' is not defined won't show up any more
You can configure JSHint by adding "require" to the .jshintrc file. For instance:
{
"globals" : {
"require": false
}
}
Or you can define globals per specific file only by:
/* global require */
For more information about how to configure JSHint please read JSHint Documentation
I stumbled upon this answer and couldn't get anything to work in VSCode. I got this to work:
Open JSON Settings file using the Preferences: Open Settings (JSON) via the Command Palette Window (Ctrl-Shift-P).
Add this section into the settings.json file:
{
"jshint.options": {
"esversion": 8, // This gets rid of some other warnings
"node": true
}
}