Express, Pug and Webpack - node.js

I have a Node js server app which uses Express and Pug. I would like to bundle it to single script which can be deployed by pm2. There seem to be several problems with this.
In runtime I get Cannot find module "." and during compilation few messages like
WARNING in ./node_modules/express/lib/view.js 80:29-41 Critical
dependency: the request of a dependency is an expression
appear which come from dynamic imports like require(mod).__express. I assume Webpack can't statically resolve those and does not know which dependency to include.
How can this be solved ?
How do I make Pug compile and be part of the output js ?

It is because webpack rebundle node_modules (already bundled) dependencies and in the case of pug, it doesn't work.
You need to use webpack-node-externals within the webpack externals option in order to specifically ask not to re-bundle depedencies.
Install webpack-node-externals: npm i -D webpack-node-externals
Integrate it your webpack config file:
Example
// ...
const nodeExternals = require('webpack-node-externals')
module.exports = {
target: 'node',
entry: {
// ...
},
module: {
// ...
},
externals: [nodeExternals()],
output: {
// ...
},
}

Related

webpack doesn't bundle node modules

I want to require a module from node_modules and I want to bundle it (for test purposes), but Webpack behaves as if it is added to externals.
// no externals or any plugin used
let config = {
mode: 'none',
target: 'node',
entry: {
output: `/example.js`,
},
resolve: {
extensions: ['.js'],
},
output: {
path: './dist',
},
};
// exampl.js
require('path')
// dist/output.js
require('path');
Expected behavior
the node module path to be bundled
actual behavior
Webpack keep require('path');
This is by design. When you set target: 'node' in webpack config, webpack will not bundle the built-ins module of Node.js. path is a built-in module of Node.js, it doesn't come from the node_modules directory.
using node webpack will compile for usage in a Node.js-like environment (uses Node.js require to load chunks and not touch any built in modules like fs or path).
See targets

Webpack and vue-loader to work with a dependency

I have a privately built dependency that is compiled down to commonjs in my project.
Within the dependency itself, it references a file in my project, a vue file. After building with webpack, and using ssr, it seems to have an issue. It fails to load the vue file.
For clarity, folder structure:
node_modules
|
|- dependency
|
|-main.js
src
|
|-pages
|
|-Default.vue
dist
|
|-compiledcode.js <- what webpack compiles
Now in main.js of the dependency, I have const vuefile = require('../../src/pages/Default.vue')
The error as displayed by Node once hosting it via ssr:
<template>
^
SyntaxError: Unexpected token '<'
In my webpack i have the following:
module.exports = {
...
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
...
]
},
plugins: [
new VueLoaderPlugin()
...
]
}
From how I am understanding the error is that vue-loader isn't loading in the file. But I don't even know this is possible to begin with. If there can be clarification on this.
If not possible ..
Is it possible to then add a webconfig to the dependency and make it work that way? If so, how do I get my webpack to interact with the dependencies webpack.
Thanks.
can you please show your whole config?
set webpack resolve (incl extension resolve)
is vue included in main.js? (import vue..)
setup alias to prevent paths like '../../src/pages/..'

"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.

Webpack fails with Node FFI and Typescript - dynamic require error

In a simple Typescript program I require Node FFI with
import * as Electron from 'electron';`
import * as ffi from 'ffi';`
and then
mylib = ffi.Library('libmoi', {
'worker': [ 'string', [ 'string' ] ],
'test' : [ 'string', [] ]
} );
Linking that up via webpack yields
WARNING in ./~/bindings/bindings.js
Critical dependencies:
76:22-40 the request of a dependency is an expression
76:43-53 the request of a dependency is an expression
# ./~/bindings/bindings.js 76:22-40 76:43-53
The problem seems to be that FFI has a dynamic require and the fix seems to be to apply webpack.ContextReplacementPlugin in the webpack.config.js file.
This is a bit out of my reach, but an example for an Angular case is:
plugins: [
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
root('./src') // location of your src
)
]
Any idea how to do this for FFI?
Here is the answer: github issue comment on the Johnny-Five repo
Quoting from brodo's answer, this is what you do to stop webpack getting snarled up with "bindings" and similar:
... the webpack config looks like this:
module.exports = {
plugins: [
new webpack.ContextReplacementPlugin(/bindings$/, /^$/)
],
externals: ["bindings"]
}
I also had a similar issue, somehow, I managed to resolve it. I will first explain my understanding.
Main work of webpack is to bundle the separate code file into one file, by default it bundles all the code that is referenced in its tree.
Generally two types of node_modules:
To be used on browser side(angular, rxjs etc)
To be used on nodejs side(express, ffi etc)
It is safer to bundle browser side node_module but not safer to bundle node side node_module because they are not designed like that So the solution is below two steps:
Give appropriate target(node, electron etc) in webpack.config.js file e.g "target":'electron-renderer' by default it is browser
Declare node_side module as external dependency in your webpack.config.js file e.g.
"externals": {
"bindings": "require('bindings')",
"ffi": "require('ffi')"
}

Angular 2 how to load 3rd party vendor node modules with sub dependencies angular-cli

Loading a single node module in Angular 2 an angular-cli bootstraped project is described within the wiki pretty well. Just being curious, how do I nicely load a more complex node module within a project bootstrapped with angular-cli?
E.g. angular2-apollo relies on several sub-dependencies like apollo-client, graphql, lodash, ...
I added the node module to angular-cli-build.js
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
'...',
'angular2-apollo/**'
]
});
};
And registered the node module ins system-config.js with
const barrels: string[] = [
// ...
// Thirdparty barrels.
'rxjs',
'angular2-apollo',
// App specific barrels.
// ...
];
// ...
// Apply the CLI SystemJS configuration.
System.config({
map: {
'#angular': 'vendor/#angular',
'rxjs': 'vendor/rxjs',
'angular2-apollo':'vendor/angular2-apollo/build/src',
'main': 'main.js',
},
packages: cliSystemConfigPackages
});
However this is only loading angular2-apollo. The sub-dependencies of angular2-apollo are not getting loaded. How do I load subdependencies with system.js within angular-cli bootstraped project?
So, you are facing a really annoying problem with System.js and there is an open issue about that on the Angular CLI here: https://github.com/angular/angular-cli/issues/882
It basically means you have to specify all the dependencies in the system.config.ts file and load them all in the angular-cli-build.js file.... horrible I know...
Maybe in the future that will happen: https://github.com/angular/angular-cli/issues/909
But, until the Angular CLI will become better, here is a starter app that includes Angular 2.0 and angular2-apollo with all it's dependencies (and even with a mock GraphQL server..) - https://github.com/Urigo/apollo-ship
You can check out the system.config.ts and the angular-cli-build.js in there to see how to include dependencies on angular2-apollo, apollo-client, lodash (and all the wanted dependencies of it), redux and many many more (too many....)
I think you are doing wrong in system.config.ts. User package configuration should be in the upper section of this file.
const map: any = {
'angular2-apollo': 'vendor/angular2-apollo/build'
};
/** User packages configuration. */
const packages: any = {
'angular2-apollo': { main: 'main.js', defaultExtension: 'js' },
};
See if it helps you ?

Resources