Fable, Webpack, and Native Node.js Modules...

Created on 16 Mar 2018  Â·  4Comments  Â·  Source: fable-compiler/Fable

I have a basic Node.js console application set up to use Fable via Webpack. My config file has the basic setup, with the fable-loader configured to handle F# files (I'm also using the BundleAnalyzerPlugin to help visualize what is in my bundle):

let path = require("path");
let webpack = require("webpack");
let fableUtils = require("fable-utils");
let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const resolve = filePath => path.join(__dirname, filePath);

let babelOptions = fableUtils.resolveBabelOptions({
    presets: [["env", { "modules": false }]],
    plugins: ["transform-runtime"]
});

module.exports = {
    entry: resolve("./src/Console.fsproj"),
    output: {
        path: resolve("./app"),
        filename: "Console.js"
    },
    resolve: { modules: [resolve("node_modules")] },
    module: {
        rules: [
            {
                test: /\.fs(x|proj)?$/,
                use: {
                    loader: "fable-loader",
                    options: { babel: babelOptions, define: ["DEBUG"] }
                }
            }
        ]
    },
    devtool: "source-map",
    mode: "development",
    watch: true,
    target: "node",
    externals: {
        serialport: {
            commonjs: "serialport"
        }
    },
    plugins: [new BundleAnalyzerPlugin()]
};

I am trying to use node-serialport (https://github.com/node-serialport/node-serialport). From their documentation and various GitHub issues, it seems they do not support Webpack, and in fact, Webpack in general seems to choke on Native Node.js modules. The solution seems to be to use the Webpack externals option as I have used it above (although, admittedly, I am pretty confused on what exactly it is supposed to do, other than simply exclude the module from my bundle).

From this point, I get a successful Webpack compilation and try to run my code:

module Console

open Fable.Core.JsInterop

let serialPort: obj = importDefault "serialport"

printfn "%A" serialPort

However, it prints undefined. I've tried a few other of the import functions as well as trying to use Emit and jsNative to generate a standard require call, but none of that works either, likely because Webpack has completely changed the meaning of require. I've even tried some shenanigans with the webpack.IgnorePlugin (https://webpack.js.org/plugins/ignore-plugin/) or trying to Emit a call like eval('require(\"serialport\")'); but no luck :^)

So what's the story on this? Ultimately, I need to get this up and running with Electron as well, but I figured testing it out in a Node.js console application would be easier to start. Surely it's possible to use Fable + Webpack + Native Node.js modules?

Most helpful comment

I made it work with this change:

  externals: {
    serialport: "commonjs serialport"
  }

I followed this blog post: https://jlongster.com/Backend-Apps-with-Webpack--Part-I

All 4 comments

Hmm, I haven't worked with Node native modules, so I'm not sure. But if you're writing a Node app and have problems with webpack, you may want to try fable-splitter just using Babel commonjs plugin as in here (you can omit the fableCore part in that config).

I'll give that a shot, thanks. It'll be a bummer to not be able to use Webpack (won't be able to use HMR), but I think it's really a lack of documentation on Webpack's end at this point. I will probably play around with some other solutions and see what works and what doesn't

I made it work with this change:

  externals: {
    serialport: "commonjs serialport"
  }

I followed this blog post: https://jlongster.com/Backend-Apps-with-Webpack--Part-I

Thanks that works great! I am still hopelessly confused as to _why_ it works, since it doesn't match any of the outlined techniques in their docs (https://webpack.js.org/configuration/externals/), but ¯\_(ツ)_/¯

As a more general solution, I am going to use webpack-node-externals (https://www.npmjs.com/package/webpack-node-externals) which does exactly this,
but for every package you have, forcing you to manually white-list the ones you want bundled rather than the other way around.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stkb picture stkb  Â·  3Comments

alfonsogarciacaro picture alfonsogarciacaro  Â·  3Comments

krauthaufen picture krauthaufen  Â·  3Comments

SirUppyPancakes picture SirUppyPancakes  Â·  3Comments

tomcl picture tomcl  Â·  4Comments