Build express server with webpack typescript and esm
Asked Answered
I

1

7

I'm trying to build a small project node.js + ts using webpack.

tsconfig.json
{
  "compilerOptions": {
    "lib": ["ESNext"],
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "types": ["node"],
    "allowSyntheticDefaultImports": true,
    "rootDir": "./"
  },
}

I added it to the package.json line "type": "module"

webpack.config.ts
import * as path         from 'path';
import * as webpack      from 'webpack';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const PATHS = {
  entry:  path.resolve(__dirname, 'src/server/index.ts'),
  output: path.resolve(__dirname, 'dist'),
};

const config: webpack.Configuration = {
  target:  'node',
  entry:   PATHS.entry,
  output:  {
    path:     PATHS.output,
    filename: 'bundle.js',
  },
  module:  {
    rules: [
      {
        test:    /\.ts(x?)$/,
        use:     'ts-loader',
        exclude: '/node_modules/',
      },
    ],
  },
  resolve: {
    extensions: ['*', '.js', '.jsx', '.json', '.ts', '.tsx'],
  },
};

export default config;

By running the command "build": "webpack --config config/webpack.config.ts --mode development", I get an error :

[webpack-cli] Failed to load '/node_esm/webpack.config.ts' config [webpack-cli] TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /node_esm/webpack.config.ts

I tried adding to my config.json "ts-node": { "esm": true} this didn't help solve my problem. What do I need to do in order to build an application using webpack?

  • node: v16.18.1
  • ts-loader: v9.4.2
  • typescript: v4.9.4
  • webpack: v5.75.0
  • webpack-cli: 5.0.1

UPD I've tried change tsconfig.The first option is to open your tsconfig.json file and look for compilerOptions. Set target to "ES5" and module to "CommonJS" (or completely remove the module option).

{
  "compilerOptions": {
    "target": "ES5",
    "module": "CommonJS",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "types": ["node"],
    "allowSyntheticDefaultImports": true,
    "rootDir": "./"
  }
}

the error remained the same. The second option is to add settings for ts-node:

You can keep "module": "ESNext" for tsc, and if you use webpack, or another build tool, set an override for ts-node.

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true,
    "types": ["node"],
    "allowSyntheticDefaultImports": true,
    "rootDir": "./"
  },
  "ts-node": {
    "compilerOptions": {
      "module": "CommonJS"
    }
  }
}

also at this point I tried to add

{
  "compilerOptions": {
    "module": "ESNext" // or ES2015, ES2020
  },
  "ts-node": {
    // Tell ts-node CLI to install the --loader automatically, explained below
    "esm": true
  }
}

as stated in the typescript documentation. The third option is to install the tsconfig-paths package it also didn't help.in all cases, the error remained the same as it was written before.

package.json
{
  "name": "node_esm",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "watch": "webpack --config config/webpack.config.ts --mode development --watch",
    "build": "webpack --config config/webpack.config.ts --mode development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cross-env": "^7.0.3",
    "express": "^4.18.2"
  },
  "devDependencies": {
    "@types/express": "^4.17.15",
    "@types/node": "^18.11.18",
    "@types/webpack": "^5.28.0",
    "circular-dependency-plugin": "^5.2.2",
    "clean-webpack-plugin": "^4.0.0",
    "nodemon": "^2.0.20",
    "ts-loader": "^9.4.2",
    "ts-node": "^10.9.1",
    "tsconfig-paths": "^4.1.2",
    "tsconfig-paths-webpack-plugin": "^4.0.0",
    "typescript": "^4.9.4",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1",
    "webpack-node-externals": "^3.0.0"
  }
}
Incursive answered 20/1, 2023 at 7:38 Comment(14)
You need to start the webpack build with ts-node. Did you read webpack.js.org/configuration/configuration-languages/…?Orian
@Orian yes, I tried to do as it is written in the documentation, but it didn't help.Incursive
How are you starting the webpack build?Orian
@Orian I wrote the command how I run webpack in question.Incursive
Then you don't read documentation clearly. You're not using ts-node.Orian
@Orian what is it about? I might have missed something in the documentation. I tried specifying ts-node in tsconfig.Incursive
@Phil yes, im intsall all deps. I tried all 3 options, the error remained the sameIncursive
@Phil Of course I tried them separatelyIncursive
Thanks for updating. The error you're seeing is from ts-node. See Can't run my Node.js Typescript project TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /app/src/App.ts. At this stage I'd be weighing up how useful Webpack is for this project. You could also save some pain and just use JS for the Webpack configCurran
Is there a reason you're using a web bundler to build your server-side app?Curran
Not trying to troll, but why put yourself through this pain? I've managed an in-house Webpack app for years and I'm happy to say that I will never do it again. Webpack is intended for libraries and not so much applications. I suggest something like Next.js or Create React App.Carduaceous
can you pls provide the code repo or create a reproducible code base?Nne
@Carduaceous OP's title says "Build express server". The question isn't even tagged with reactjs. Laughably, both Next.js and Create React App also build on Webpack so it's not clear at all where you're going with your comment about librariesCurran
@Curran "Webpack is intended for libraries and not so much applications." Looks like I wrongly assumed the OP's intended use.Carduaceous
C
4

The main issue is that Webpack uses the ts-node API, not the CLI so you need to configure the node loader appropriately.

I got it working using the following configuration.

package.json

"scripts": {
  "build": "NODE_OPTIONS='--loader ts-node/esm' webpack --mode development"
},

See the ts-node documentation on Native ECMAScript modules...

If you are not using our CLI, pass the loader flag to node.

You may want to use something like cross-env or env-cmd if you plan on building this on Windows.


Note: I didn't need anything special in tsconfig.json. No ts-node section is required since that only applies to the CLI.


Aaaaand, I just found this troubleshooting guide in the Webpack CLI reference

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for ./webpack.config.ts

You might encounter this error in the case of using native ESM in TypeScript (i.e. type: "module" in package.json).

webpack-cli supports configuration in both CommonJS and ESM format, at first it tries to load a configuration using require(), once it fails with an error code of 'ERR_REQUIRE_ESM' (a special code for this case) it would try to load the configuration using import(). However, the import() method won't work with ts-node without loader hooks enabled (described at TypeStrong/ts-node#1007).

To fix the error above use the following command:

NODE_OPTIONS="--loader ts-node/esm" npx webpack --entry ./src/index.js --mode production

The SEO on that page must be terrible. Hopefully linking it here helps boost it a little.

Curran answered 24/1, 2023 at 7:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.