How to bundle node project into one file - node.js

Is there any WORKING way how to bundle node project into one single file (including dependencies) and how?
I am using babel (.babelrc)
{
"presets": ["#babel/preset-env"],
"plugins": [
[
"module-resolver",
{
"root": [
"./src"
],
"alias": {
"test": "./test",
"underscore": "lodash"
}
}
]
]
}

the answer is no. babel can not do what you want by itself. It is a tool for transforming one dialect of Javascript into another, based on rules defined in your .babelrc file. It is a compiler, not a linker (to borrow terms from the C world).
Using babel-plugin-module-resolver will not cause babel to transpile dependencies as if they were source files. It is simply a babel rule which modifies the paths passed to require() or import.
To include dependencies as well as source files you need to use both a compiler like babel and a bundler such as webpack or rollup.

Related

Force TypeScript to generate export/imports with the ".js" extension; running Node 16?

Have a TS 4.7 library using ESM modules.
tsconfig.json:
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020"],
"moduleResolution": "node",
package.json
"type": "module",
I have a main file with only a one silly export:
index.ts
export { Spig } from './spig';
which is compiled to:
index.js
export { Spig } from './spig';
//# sourceMappingURL=index.js.map
Problem
When I use this library from a Node CLI program (with ESM modules enabled as well), I get the following error:
Cannot find module <path>/lib/spig imported from <path>/lib/index.js
When I manually add .js in the generated index.js, the issue is gone:
export { Spig } from './spig.js';
How can I force TypeScript compiler to generate the extension, too? What am I missing here?
You cannot omit the file extension anymore in ESM module imports. The extension should be always .js/.jsx, not .ts/.tsx for a typescript file. So, in the index.ts you should add the extension to spig export like the following and every other file imported/exported if using ESM modules.:
index.ts
export { Spig } from './spig.js';
Also, moduleResolution should be set to Node16 or NodeNext so ESM modules work as expected.
As stated in the docs (enphasis by me):
Relative import paths need full extensions (e.g we have to write import "./foo.js" instead of import "./foo").
When a .ts file is compiled as an ES module, ECMAScript import/export syntax is left alone in the .js output; when it’s compiled as a CommonJS module, it will produce the same output you get today under module: commonjs.
This also means paths resolve differently between .ts files that are ES modules and ones that are CJS modules. For example, let’s say you have the following code today:
// ./foo.ts
export function helper() {
// ...
}
// ./bar.ts
import { helper } from "./foo"; // only works in CJS
helper();
This code works in CommonJS modules, but will fail in ES modules because relative import paths need to use extensions. As a result, it will have to be rewritten to use the extension of the output of foo.ts - so bar.ts will instead have to import from ./foo.js.
// ./bar.ts
import { helper } from "./foo.js"; // works in ESM & CJS
helper();
This might feel a bit cumbersome at first, but TypeScript tooling like auto-imports and path completion will typically just do this for you.

How to include Node.js native modules while compiling to .exe

I'm using pkg to compile my Node.js project into an executable.
The project includes a native module called "node-printer".
Pkg has problems compiling this module, because when i run the executable i get this error:
pkg/prelude/bootstrap.js:1359
throw error;
^
.....
(internal/modules/cjs/loader.js:1218:10),Module.load (internal/modules/cjs/loader.js:1047:32)] {
code: 'MODULE_NOT_FOUND',
requireStack: [
'C:\\snapshot\\ckiosk\\node_modules\\printer\\lib\\printer.js',
'C:\\snapshot\\ckiosk\\controllers\\receiptController.js',
'C:\\snapshot\\ckiosk\\api\\ajax.js',
'C:\\snapshot\\ckiosk\\webApp.js',
'C:\\snapshot\\ckiosk\\main.js'
]
This is from the pkg readme:
Native addons (.node files) use is supported. When pkg encounters a .node file in a require call, it
will package this like an asset. In some cases (like with the bindings package), the module path is
generated dynamicaly and pkg won't be able to detect it. In this case, you should add the .node file
directly in the assets field in package.json.
Here is the pkg in my package.json file
"pkg": {
"scripts": [
"config/*.js"
],
"assets": [
"views/*",
"views/**/*",
"config/*",
"public/assets/**/*",
"node_modules/printer/lib/node_printer.node"
],
"targets": [
"node14-win"
]},
As you can see, i've included the node printer .node file in the assets, but the result is still the same.
What am i missing?
Turns out i have been using the wrong command to build.
I used this
pkg "main.js" -t node14-win -o build/ckiosk.exe
But to make use of the configuration in package.json we have to use
pkg .

Intellisense for module-alias Package

I am using this npm module (module-alias)
https://www.npmjs.com/package/module-alias in my Node project.
To make use of this package you have to set path aliases in the package.json file.
However, using this package comes with the disadvantage, that intellisense doesn't work anymore.
My question is how to enable intellisense with those path aliases?
The problem is that you did not register those aliases anywhere with your linter. I would gerenally suggest to use ESLint here (even if you use TypeScript as TSLint will be discontinued in favour of ESLint). My examples will include the TypeScript endings as well. If you definately want to make it work for JavaScript only you can skip the .ts .tsx extentensions in the eslint) So to make intellisense work do this in
.eslintrc.js
settings: {
"import/resolver": {
alias : {
map: [
["#","./src"]
],
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
}
},
Note that in this case you will need the import Plugin for ESLint. If you don't already have it install it.
If you are using TypeScript you will also have to make that alias known to your compiler. So add this to your
tsconfig.json
"compilerOptions": {
"baseUrl": ".",
"paths": [
"#/*" : [
"src/*"
]
]
}

How to transform ES2017 to ES5

I have a es2017 code with async/await, I want to transform it to es5 so that it'll be supported by most Node.js versions.
My current .babelrc file looks like this:
{
"presets": ["es2015", "es2016", "es2017"]
}
So I'm transforming es2017 to es2016, from es2016 to es2015 and from es2015 to es5.
When I'm trying to run the code after I built it with babel src -d dist -s I'm getting error saying that: ReferenceError: regeneratorRuntime is not defined
How can I transform the es2017 code to es5? I wanna publish the code later and make it usable by node.js v4 and up.
Thanks to #Bergi I found a way how to solve this ReferenceError: regeneratorRuntime is not defined error.
I added the transform-runtime plugin to my .babelrc
Now my .babelrc is:
{
"presets": ["es2015", "es2016", "es2017"],
"plugins": ["transform-runtime"]
}
There aren't any errors now and it works fine.

Make babel exclude test files

On my build step I'm using babel to transpile the code to es5 (from src to dist). How do I make it exclude files ending in .test.js?
package.json
"scripts": {
"build": "babel src --out-dir dist",
.babelrc
{
"presets": [ "es2015" ],
"ignore": "\\.test\\.js"
}
Based on the documentation, you should be able to write .babelrc
{
"ignore": [
"**/*.test.js"
]
}
However, I was able to verify that this does not seem to work. I tried it with version 6.5.1 (babel-core 6.5.2).
At the same time, the following does work:
babel src --out-dir build --ignore '**/*.test.js'
That is the same glob pattern as written in the .babelrc file. If you install any glob library from npm you'll find that this glob pattern would work (that is how I came up with it...I do not currently use babel).
As of today, the following works in .babelrc
(babel-core: v6.26.3)
"ignore": [
"**/__tests__", // ignore the whole test directory
"**/*.test.js" // ignore test files only
]

Resources