How to use relative paths with node-loader and native addon - node.js

I have a native addon I am using that works great on my dev machine but fails on any other machine due to the webpack build using an absolute path to the native module instead of a relative one. Here is the error I get:
/main.prod.js:7543: Uncaught Error: Cannot open /Users/.../app/lib/main.node: Error: dlopen(/Users/.../app/lib/main.node, 1): image not found
In my main.dev.js I import the file like this: import main from './lib/main.node';
In webpack config I have added a module test for .node:
export default {
externals: Object.keys(externals || {}),
module: {
rules: [{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
}, {
test: /\.node$/,
use: 'node-loader'
}]
},
...
How can I make sure that my main.node file gets packaged for the build and imported via relative path?

I was able to resolve this issue by switching to a modified version of node-addon-loader. https://github.com/smt116/node-native-ext-loader

Related

Module parse failed for one specific node_module, how do you solve it? (details inside)

I have a project, that when I build the UI, it keeps returning “Module parse failed”.
The problem is VERY similar to this one https://github.com/TypeStrong/ts-loader/issues/867, the only difference is that instead of a static variable, it is the initialization of a variable, like this:
export class AppWebsocket {
client; // WEBPACK SAYS THIS LINE HAS THE ERROR
defaultTimeout;
overrideInstalledAppId;
constructor(client, defaultTimeout, overrideInstalledAppId) {
// Some code
}
}
This problem appears after I am importing something new from a new dependency (the AppWebsocket). The AppWebsocket belongs to a new dependency I’ve installed. And I am importing the AppWebsocket in one of my files.
The problem to this is related to webpack and the rules for the modules according to the link.
On my webpack configuration I have this:
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-react'],
plugins: [],
},
},
},
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: 'ts-loader',
},
The problem seems to be fixed, if I turn it into this:
{
test: /\.js$/,
use: 'ts-loader',
},
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: 'ts-loader',
},
The problem is that I don’t understand what are the consequences of this. My project uses react.
I need to solve the webpack problem, but I am not sure what I am doing. Any help to understand or to fix this issue is appreciated.

Node.js: How to import test files in custom test runner

I'm trying to create my own custom testing framework for learning purpose. Test files are written in following way
import { somemethod } from './some/module'
test(/I click on a button)/, () => {
browser.get("someSelector").should("have.text",somemethod());
});
I user require(file) to load test files. But it throw error SyntaxError: Unexpected token {
for import statement in test file. I'm using node js version 11.15.
If I switch to node v13.14 and define "type": "module" in my package.json then it doesn't let me use require(file) to load a test file or any module in my package.
How can I import tests files considering the user may be importing the modules using import or require?
This answer is very empirical...
Considering that it works using canonical commonjs approach you can try to debug it with newer version of NODE (currently I would use 14). For it, I would suggest you to use a node version manager like NVM so you can switch between node version easily and test that accordling seeing differences between various node installations.
Make a minimal project with npm init with a single dependency, save your index with the .mjs extension and try an import the above dependency. If you are be able to import that dependency with that minimal environment you can blame either your previous node or your configuration or both of them.
At the moment you should only create a small 2 files project to reproduce the problem. It seems your current node does not consider the "type": "module" configuration and runs everything in its classic way.
Regarding your comments....
As far as I know import can be used even in your code, not just at the beginning:
(async () => {
if (somethingIsTrue) {
// import module for side effects
await import('/modules/my-module.js');
}
})();
from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
Additionally you can try Webpack with a configuration like:
// webpack.config.js
const nodeExternals = require('webpack-node-externals');
module.exports = {
mode: 'production',
target: 'node',
externals: [nodeExternals()],
entry: {
'build/output': './src/index.js'
},
output: {
path: __dirname,
filename: '[name].bundle.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
['env', {
'targets': {
'node': 'current'
}
}]
]
}
}
}]
}
};
With NodeExternals you don't put your node dependencies in the bundle but only your own code. You refer to node_modules for the rest. You might not want that.

Typescript Definition Files in Webpack

Okay, so I have a Typescript definition file model.d.ts. It contains definitions for the classes used in my business logic, so that I can have strong typing in my Vue.js files.
I have a Vue.js template person.vue, with a code section that looks like this:
<script lang="ts">
import axios from "axios";
import * as _ from "lodash";
import * as model from "model";
// ...
</script>
But when I try to build this with Webpack, I run into problems:
ERROR in I:\git\myapp\src\component\person-page\person.vue.ts
[tsl] ERROR in I:\git\myapp\src\component\person-page\person.vue.ts(27,24)
TS2307: Cannot find module 'model'.
ERROR in ../myapp/node_modules/ts-loader!../myapp/node_modules/vue-loader/lib/selector.js?type=script&index=0&bustCache!../myapp/src/component/person-page/person.vue
Module not found: Error: Can't resolve 'model' in 'I:\git\myapp\src\component\person-page'
# ../myapp/node_modules/ts-loader!../myapp/node_modules/vue-loader/lib/selector.js?type=script&index=0&bustCache!../myapp/src/component/person-page/person.vue 10:14-30
# ../myapp/src/component/person-page/person.vue
# ../myapp/src/main.ts
# multi webpack-hot-middleware/client ./src/main.ts
I'm using ts-loader, and the relevant parts of my webpack.config.js look like this:
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /.ts$/,
use: {
loader: "ts-loader", options: {
appendTsSuffixTo: [/\.vue$/]
}
},
exclude: /node_modules/
},
// ...
{
test: /\.vue$/,
loader: "vue-loader"
}
]
},
resolve: {
extensions: [".ts", ".js", ".vue", ".json"],
alias: {
"vue$": "vue/dist/vue.esm.js"
}
}
};
Why doesn't my definition file work, and how can I make it so that it can be used in person.vue?
I think you have a problem with your path. "model" should point to the complete path to the model.d.ts without the file extensions.

Mp3 files and Vue-loader

I'm tying to load a mp3 file in my Vue component: (I'm using the Vue-CLI boilerplate)
const sound = new Audio(require("./sound.mp3")))
But I'm getting this error:
Unexpected character ‘’ (1:3)
You may need an appropriate loader to handle this file type.
Here is a minimal project demonstrating the error: https://github.com/life4ants/vue-audio-test
adding the following to build/webpack.base.conf.js fixed the problem:
{
test: /\.mp3$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
the app at the above link has been updated and now works.

How do I load font-awesome using SCSS (SASS) in Webpack using relative paths?

I have font-awesome in my node_modules folder so I try to import it in my main .scss file like so:
#import "../../node_modules/font-awesome/scss/font-awesome.scss";
But Webpack bundling compilation fails, telling me
Error: Cannot resolve 'file' or 'directory' ../fonts/fontawesome-webfont.eot
because the font-awesome.scss file refers to a relative path, '../fonts/'.
How can I tell scss \ webpack to #import another file, and use that file's folder as the home folder so that its relative paths work as it expects?
Use
$fa-font-path: "~font-awesome/fonts";
#import "~font-awesome/scss/font-awesome";
where the $fa-font-path variable is seen in font-awesome/scss/_variables.scss
$fa-font-path: "../fonts" !default;
The tilde "~" is interpolated by sass-loader using the webpack mecanism.
There doesn't appear to be any way to #import files that have their own relative paths in SCSS \ SASS.
So instead I managed to get this to work:
Import the scss \ css font-awesome file in my .js or .jsx files, not my stylesheet files:
import 'font-awesome/scss/font-awesome.scss';
Add this to my webpack.config file:
module:
{
loaders:
[
{test: /\.js?$/, loader: 'babel-loader?cacheDirectory', exclude: /(node_modules|bower_components)/ },
{test: /\.jsx?$/, loader: 'babel-loader?cacheDirectory', exclude: /(node_modules|bower_components)/ },
{test: /\.scss?$/, loaders: ['style-loader', 'css-loader', 'sass-loader']},
{test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?mimetype=image/svg+xml'},
{test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/font-woff"},
{test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/font-woff"},
{test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader?mimetype=application/octet-stream"},
{test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file-loader"},
]
}
Following worked for me:
$fa-font-path: "~font-awesome/fonts";
#import "~font-awesome/scss/font-awesome";
This is to import the font-awesome & required fonts in the project.
Other change is in webpack configurations, to load required fonts using file-loader.
{
test: /\.scss$/,
loaders: ['style', 'css?sourceMap', 'sass'
],
}, {
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?.*$|$)/,
loader: 'file'
}
This is how it worked for me, the trick is to set $fa-font-path to the path of the fonts as following.
$fa-font-path: "~#fortawesome/fontawesome-free/webfonts/";
#import '~#fortawesome/fontawesome-free/scss/fontawesome.scss';
#import '~#fortawesome/fontawesome-free/scss/solid.scss';
#import '~#fortawesome/fontawesome-free/scss/brands.scss';
Note: Please check your fonts folder in node_modules in my case it is #fortawesome/fontawesome-free
Resolved by changing my app.scss:
#import '~font-awesome/scss/_variables.scss';
$fa-font-path: "~font-awesome/fonts";
#import '~font-awesome/scss/font-awesome.scss';
This way is useful to keep external dependencies unchanged and unversioned.
I just set the path in my main scss file and it works :
$fa-font-path: "../node_modules/font-awesome/fonts";
#import '~font-awesome/scss/font-awesome.scss';
What worked for me was to add resolve-url-loader and enable sourceMaps
I already imported font-awesome in my root .scss file:
#import "~font-awesome/scss/font-awesome";
...
This root file is imported in my main.js file defined as Webpack's entrypoint:
import './scss/main.scss';
...
Then my final webpack module rules look like so:
...
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{ loader: 'postcss-loader', options: { sourceMap: true }, },
'resolve-url-loader',
{ loader: 'sass-loader', options: { sourceMap: true }, },
],
}, {
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: { limit: 1000, name: 'fonts/[name].[ext]', },
}
...
Note:
I used mini-css-extract-plugin, which can be registered like this:
new MiniCssExtractPlugin({
filename: 'css/main.css',
chunkFilename: '[id].[hash]',
}),
url-loader requires file-loader to be installed, so if you get an error like: cannot find module file-loader, then just install it:
npm i -D file-loader
Useful Links:
https://github.com/webpack/webpack/issues/2771#issuecomment-277514138
https://github.com/rails/webpacker/issues/384#issuecomment-301318904
For Version 5.14, the following worked for me:
$fa-font-path : '../node_modules/#fortawesome/fontawesome-free/webfonts';
#import "../node_modules/#fortawesome/fontawesome-free/scss/solid";
#import "../node_modules/#fortawesome/fontawesome-free/scss/brands";
#import "../node_modules/#fortawesome/fontawesome-free/scss/fontawesome";
v.4 (symofony 4 + webpack)
$fa-font-path: "~components-font-awesome/webfonts";
#import '~components-font-awesome/scss/fa-brands';
#import '~components-font-awesome/scss/fa-regular';
#import '~components-font-awesome/scss/fa-solid';
#import '~components-font-awesome/scss/fontawesome';

Resources