Anwendung vom ESM Modulen im Browser
bearbeitet von
Update: Ich konnte file-type jetzt mit Webpack 5 zum **Übersetzen** bringen, aber es ist eine Quälerei. Der Autor pfeift auf den Browser und entwickelt primär für Node - es gibt keine Doku, was man alles tun muss, damit es im Browser funktioniert.
(1) Man muss seinen eigenen Code in ein ES6-Modul stecken
(2) Man muss entweder aus seinem Modul heraus eine globale Variable setzen, um auf exportierte Elemente zugreifen zu können, ODER man muss nach jeder Codeänderung Webpack neu laufen lassen. Denn ein export Statement wird von Webpack nicht ins Bundle übertragen.
Sodann muss man im Projektordner
npm install webpack --save-dev
npm install webpack-cli --save-dev
npm install buffer
npm install file-type
ausführen, und nun kommt der Extraspaß: Das richtige Setup von Package und Webpack.
In der package.json wird gebraucht:
- "private": "true"
- "type": "module"
Die webpack.config.js, die in allen Beispielen mit module.exports hantiert, funktioniert in einem ESM-Projekt natürlich anders. Man muss das Config-Objekt nicht an module.exports zuweisen, sondern als Default exportieren:
~~~js
const nodeResolverPlugin = ?!?!?!;
const distPath = ?!?!?!;
export default {
entry: "./src/main.js",
output: {
path: distPath,
filename: 'app.js'
},
mode: "production",
plugins: [ nodeResolverPlugin ]
};
~~~
Im src Order steht der js Code, den man selbst schreibt. Webpack bündelt das zusammen mit allen node-modules und schreibt es in den output-Ordner. Unter path muss ein **absoluter** Path angegeben werden. Das kann man so lösen:
~~~js
import path from 'path';
const distPath = path.resolve("./dist");
~~~
dist steht für Distribution, und die Angaben von ./src und ./dist setzen voraus, dass diese beiden Unterordner im gleichen Ordner wie die webpack.config.js stehen.
Für Code in der webpack.config.js kann man munter mit Node-Libraries herumhantieren, weil dieses Script von Webpack ausgeführt wird, also in der Node-Umgebung.
Das nodeResolverPlugin ist lebensnotwendig, das habe ich mühsam aus den Issues vom file-type Projekt herausgefunden. Einige der Dependencies von file-type verwenden nämlich `import xyz from 'node:stream' - und das will man nicht - der Code soll ja im Browser laufen. Deshalb schreibt man diesen Helper (1:1 aus den Issues kopiert):
~~~js
import webpack from 'webpack';
const nodeResolverPlugin = new webpack.NormalModuleReplacementPlugin(/node:/, (resource) => {
const mod = resource.request.replace(/^node:/, "");
switch (mod) {
case "buffer":
resource.request = "buffer";
break;
case "stream":
resource.request = "readable-stream";
break;
default:
throw new Error(`Not found ${mod}`);
}
});
~~~
Damit werden die diversen import ... from 'node:buffer' Anweisungen von der nodeJs Abhängigkeit befreit. readable-stream ist ein npm-Paket, das mit file-type mitkommen **sollte**, bei mir aber nicht immer mitkam. Wenn es fehlt, kann es explizit als readable-stream@3.6.2 nachinstalliert werden. Nicht die 4-er Version verwenden, die hat bei mir nur gekracht.
Damit konnte ich dann die Application durch Webpack durchlaufen lassen. Ohne Webpack geht gar nichts, weil die Import-Laufzeitumgebung von Node im Browser komplett fehlt.
Nur - ein Aufrufversuch schlug dann wieder fehl, weil eins der Module auf die Variable `process` zugreifen wollte, die in Node möglicherweise global ist und im Browser nicht existiert. Das muss man **patchen**, das scheint ein Fehler in readable-stream.js zu sein.
Man installiere noch das NPM-Modul process (Userland-Implementierung von 'node:process') und ändere in readable-stream/lib die Datei _stream_readable.js so ab:
~~~js
'use strict';
module.exports = Readable;
var process = require('process'); // <<- diese Zeile einfügen
~~~
Und HEY, nach nur wenigen Stunden läuft dieser Dreck!!!
_Rolf_
--
sumpsi - posui - obstruxi