After not touching Javascript for over a decade I had an idea for an app that will work best when implemented as a NodeJS app. I read up on the modern JS ecosystem and like most people I'm thoroughly confused, haha.
Seems like the combination of NodeJS, TypeScript and Webpack is a good way to go, but I'm having issues even getting a simple Hello World working.
The one TypeScript file I wrote, ./src/run_task.ts
:
// #!/usr/bin/env node
/**
* @file Main application file. Users start the app by running `node dist/run_task.js`
* @author Gerard Leenhouts
*/
import * as process from "process";
function main(): number {
console.log(process);
console.log(`Got ${process.argv.length} arguments.`);
return 42;
}
main();
When I execute tsc
manually (tsc -p server.tsconfig.json
) it works fine, but when I execute webpack
it seems to create it's own definition of the process
module in the resulting .js file. Here's a part of it:
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) { return [] }
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
My package.json
:
{
"name": "startpage",
"version": "1.0.0",
"description": "Self hosted web app to function as a web browser startpage",
"main": "run_task.js",
"scripts": {
"build": "webpack",
"start": "node dist/run_task.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Gerard Leenhouts",
"license": "ISC",
"devDependencies": {
"@types/node": "^9.4.6",
"ts-loader": "^3.5.0",
"typescript": "^2.7.2",
"webpack": "^3.11.0"
}
}
My webpack.config.js
:
const path = require('path');
module.exports = [
{
// devtool: 'inline-source-map',
entry: './src/run_task.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: { configFile: 'server.tsconfig.json' }
}
],
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.ts', '.tsx', '.js' ]
},
output: {
filename: 'run_task.js',
path: path.resolve(__dirname, 'dist')
}
}
];
My server.tsconfig.json
:
{
"compilerOptions": {
// "sourceMap": true,
"outDir": "./dist/",
"strict": true,
"noImplicitAny": true,
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"esModuleInterop": true,
"baseUrl": "./",
"paths": { "*": ["node_modules/*", "src/types/*"] },
"removeComments": true
},
"include": [ "./src/**/*" ]
}
I've been going through the Webpack and TypeScript documentation for hours now, and can't seem to figure it out. It's quite possible I'm overlooking something simple but I can't see the forest for the trees anymore. Obviously it has something to do with module resolution but everything seems fine in the config files, as far as I can tell. Any help is appreciated, thanks in advance!
In your
webpack.config.js
you need to set thetarget
tonode
. Just addtarget: 'node'
at the same level asoutput
. This 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 process, fs, etc). Docs here: https://webpack.js.org/concepts/targets/