Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
209 views
in Technique[技术] by (71.8m points)

How should I invoke webpack to bundle bazel's ts_library output

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It looks like the problem is that ts_library defaults its devmode_module parameter to umd. Webpack, at least as configured in the rules_nodejs example (i.e. without UMD-specific plugins) doesn't seem to be able to handle the UMD modules generated by ts_library. Changing devmode_module to es2015 solves the problem. I don't know if it's the best solution, but it results in Webpack creating a functional bundled JS file.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...