I'm trying to build a React JS app from Typescript sources, built with Bazel and using Webpack as the bundler. rules_nodejs includes examples/react_webpack, which shows how to do it using ts_project
, but I need to build it using ts_library
because ts_project
doesn't seem to do well with generated TS files (in my case protobuf TS files).
How do I get ts_library
to play nice with Webpack (or vice versa)?
Here is my attempt to adapt examples/react_webpack to use ts_library
instead of ts_project
. It uses Webpack 4 because that's what the example uses, and I wanted to minimize change. For completeness, I also have this commit which reproduces the change with Webpack 5, though it's my first time using Webpack 5 so it's possible that I introduced additional problems with the migration.
When I run bazel run server
with the Webpack 4 commit, then load the resulting page in Chrome, I get this error on console:
app.bundle.js:6 Uncaught Error: Cannot find module 'react'
at n (app.bundle.js:6)
at app.bundle.js:6
at app.bundle.js:6
at Object.<anonymous> (app.bundle.js:6)
at n (app.bundle.js:1)
at app.bundle.js:1
at app.bundle.js:1
Webpack 5 emits a similar error, though slightly more informative(?):
_sync:2 Uncaught Error: Cannot find module 'react'
at webpackEmptyContext (_sync:2)
at eval (index.tsx:7)
at eval (index.js:3)
at eval (index.js:12)
at Object../bazel-out/k8-fastbuild/bin/index.js (main.js:18)
at __webpack_require__ (main.js:172)
at main.js:188
at main.js:189
In both cases, I hit a webpack require for ./bazel-out/k8-fastbuild/bin/index.js
, which is what I've designated as my entry point (not sure if that's the right path to have specified as the entry point). This leads me into the index.js
AMD(?) module, which then requires ./bazel-out/k8-fastbuild/bin sync recursive
. That requirement seems to lead directly to the error:
/***/ "./bazel-out/k8-fastbuild/bin sync recursive":
/*!******************************************!*
!*** ./bazel-out/k8-fastbuild/bin/ sync ***!
******************************************/
/***/ ((module) => {
eval("function webpackEmptyContext(req) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
webpackEmptyContext.keys = () => [];
webpackEmptyContext.resolve = webpackEmptyContext;
webpackEmptyContext.id = "./bazel-out/k8-fastbuild/bin sync recursive";
module.exports = webpackEmptyContext;
//# sourceURL=webpack:///./bazel-out/k8-fastbuild/bin/_sync?");
One other thing I noticed:
The rules_nodejs examples/react_webpack example, using ts_project
, compiles index.tsx
like this:
"use strict";
exports.__esModule = true;
var React = require("react");
var ReactDOM = require("react-dom");
var styles = require("./styles.css");
ReactDOM.render(React.createElement("h1", { className: styles.h1 }, "Hello, world!"), document.getElementById("root"));
s
I think that's a script?
ts_library
compiles it like this, which I think is a module?
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define("react_webpack/index", ["require", "exports", "react", "react-dom"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const React = require("react");
const ReactDOM = require("react-dom");
ReactDOM.render(React.createElement("h1", null, "Hello, world!"), document.getElementById("root"));
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9pbmRleC50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7SUFBQSwrQkFBK0I7SUFDL0Isc0NBQXNDO0lBRXRDLFFBQVEsQ0FBQyxNQUFNLENBQ2IsZ0RBQXNCLEVBQ3RCLFFBQVEsQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQ2hDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCAqIGFzIFJlYWN0RE9NIGZyb20gXCJyZWFjdC1kb21cIjtcblxuUmVhY3RET00ucmVuZGVyKFxuICA8aDE+SGVsbG8sIHdvcmxkITwvaDE+LFxuICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInJvb3RcIilcbik7XG4iXX0=
Is that difference the root of the problem? Should I be trying to figure out why/how ts_project
uses the simpler form, then convince ts_library
to do the same thing? Or is it better to tell Webpack to bundle the ts_library
outputs as-is? If the latter, how?
EDIT: The ts_library
rule seems to be using a tsconfig of its own devising that sets compilerOptions.module
to umd
. Setting the same option in the ts_project
version causes index.js
to grow all the factory goo shown above.