3

Desired Behaviour

I want to be able to:

  • Use webpack to define a build process that uses babel to convert an ES6 server side Node file to "plain javascript"

Current Behaviour

If I just run:

node app.js

I get import errors:

import express from "express"; ^^^^^^^

SyntaxError: Unexpected identifier

What I've Tried

When I try and define a build process in webpack, I get errors like:

Can't resolve tls/net/fs/dns/child_process/aws-sdk/./local_settings/npm/node-gyp

There is a possible solution offered here, but it doesn't resolve all errors (these errors remain: aws-sdk, ./local_settings, npm, node-gyp):

target: "node"

There are also warnings like:

Module parse failed: Unexpected token
Critical dependency: the request of a dependency is an expression

This "how do I use ES6 in production?" question seems to be common, eg:

NodeJS in ES6/ES7, how do you do it in production?
Quickstart guide to using ES6 with Babel, Node and IntelliJ
Getting ready for production use
Is it okay to use babel-node in production

but none of the answers I have found seem definitive or specifically relate to a webpack solution.

Below is code I have now:

from webpack.config.js

const path = require('path');

console.log("the __dirname is: " + __dirname);

module.exports = {
    entry: "./src/js/app.js",
    output: {
        filename: "app.js",
        path: path.resolve(__dirname, "dist/js")
    },
    target: "node",
    mode: "development",
    module: {
        rules: [{
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: ["env", "stage-0"]
                    }
                }
            },
            {
                test: /\.css$/,
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader" }
                ]
            },
            {
                test: /\.less$/,
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader" },
                    { loader: "less-loader" }
                ]
            },
            {
                test: /\.jpg$/,
                use: [
                    { loader: "url-loader" }
                ]
            }
        ]
    }
}

from package.json:

  ...
  "main": "app.js",
  "scripts": {
    "start": "nodemon ./app.js --exec babel-node -e js",
    "build": "webpack",
    "watch": "webpack --w"
  },...
  "dependencies": {
    "bcrypt": "^2.0.1",
    "body-parser": "^1.18.2",
    "cors": "^2.8.4",
    "express": "^4.16.3",
    "jsonwebtoken": "^8.2.1",
    "mongodb": "^3.0.8"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.4",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^0.28.11",
    "file-loader": "^1.1.11",
    "less": "^3.0.4",
    "less-loader": "^4.1.0",
    "style-loader": "^0.21.0",
    "url-loader": "^1.0.1",
    "webpack": "^4.8.3",
    "webpack-cli": "^2.1.3"
  }

Question

What should my webpack.config.js and package.json files look like in order to successfully convert the ES6 file to "plain javascript"?

user1063287
  • 10,265
  • 25
  • 122
  • 218
  • For reference, I can convert es6 *without* using webpack by defining this in `package.json`: `"scripts": {"start": "nodemon dist/js/app.js", "build-server-file": "babel src/js/app.js --out-file dist/js/app.js"}`. When I run `npm run build-server-file` and then `npm start`, it seems to "work". – user1063287 May 24 '18 at 04:23

1 Answers1

2

By default, Webpack tries to bundle everything into a single .js file. For client-side projects this is fine, but for NodeJS projects it becomes slightly more complicated because you are including code from node_modules as well. Sometimes that can cause errors like the one you're seeing here.

What you want to do in addition to targets: "node" is tell Webpack not to bundle external dependencies (i.e. node_modules).

There's a useful library called webpack-node-externals that helps with this:

var nodeExternals = require('webpack-node-externals');
...
module.exports = {
    ...
    target: 'node', // in order to ignore built-in modules like path, fs, etc.
    externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
    ...
};

So it's not really about "plain javascript", more like trying to get Webpack to output a file which is compatible with the NodeJS ecosystem.

CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176
  • I really wanted to know why target: 'node' and why use webpack-node-externals library. And you solve it. Thank you :D – Byeongin Yoon Dec 15 '18 at 11:04
  • "For client-side projects this is fine, but for NodeJS projects it becomes slightly more complicated because you are including code from node_modules as well". Isn't that what front end projects also do? why is it different for node projects? – Jason Apr 06 '20 at 15:18