Issue
I have been at this for days (months if you really want to be technical). Before someone marks this as a duplicate, no, I don't want to use the ~530kb text-encoder package, noted on the thread Polyfill for TextDecoder. Additionally, fastestsmallesttextencoderdecoder does not seem to have TypeScript types and will not compile.
I am trying to make my VS Code extension compatible with the web environment of VS Code, meaning I need to create two bundles using Webpack (client and web extensions differ slightly).
In one of my source files, cheatsheet-content.ts:
import { TextDecoder } from 'util';
// ...
const htmlDocument = await vscode.workspace.fs
.readFile(
vscode.Uri.joinPath(this._cheatsheetUri, 'cheatsheet.html')
)
.then((uint8array) => {
const fileContent = new TextDecoder().decode(uint8array); // <-- ERROR
return parse(fileContent.toString());
});
I get the error (only when running as a web extension): TypeError: util_1.TextDecoder is not a constructor.
Here is my webpack.config.ts file:
/// <reference types="node" />
import * as path from 'node:path';
import { Configuration, ProvidePlugin } from 'webpack';
// eslint-disable-next-line unicorn/prefer-module
const projectRoot = __dirname;
const nodeConfig: Configuration = {
// VS Code client extensions run in Node context. See: https://webpack.js.org/configuration/node/
target: 'node',
// Leaves the source code as close as possible to the original (when packaging we set this to 'production')
mode: 'none',
// Entry point into extension (in package.json). See: https://webpack.js.org/configuration/entry-context/
entry: {
'extension.node': './src/extension.node.ts',
},
// Bundle output location. See: https://webpack.js.org/configuration/output/
output: {
filename: '[name].js',
path: path.join(projectRoot, 'dist'),
libraryTarget: 'commonjs',
devtoolModuleFilenameTemplate: '../[resource-path]',
},
devtool: 'nosources-source-map',
// Support reading TypeScript and JavaScript files. See: https://github.com/TypeStrong/ts-loader
resolve: {
extensions: ['.ts', '.js'],
alias: {
src: path.resolve(projectRoot, 'src'),
},
},
// Modules that cannot be added through Webpack. See: https://webpack.js.org/configuration/externals/
externals: {
vscode: 'commonjs vscode', // ignored because 'vscode' module is created on the fly and doesn't really exist
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader',
},
],
},
],
},
performance: {
hints: false,
},
infrastructureLogging: {
level: 'log', // enables logging required for problem matchers
},
};
const browserConfig: Configuration = {
// extensions run in a webworker context
...nodeConfig,
target: 'webworker',
entry: {
'extension.web': './src/extension.web.ts',
// 'test/suite/index': './src/web/test/suite/index.ts',
},
resolve: {
...nodeConfig.resolve,
mainFields: ['browser', 'module', 'main'], // look for `browser` entry point in imported node modules
fallback: {
// eslint-disable-next-line unicorn/prefer-module
util: require.resolve('util'), // <-- Isn't this supposed to fix my issue?
},
},
plugins: [
new ProvidePlugin({
process: 'process/browser', // provide a shim for the global `process` variable
}),
],
};
// eslint-disable-next-line unicorn/prefer-module
module.exports = [nodeConfig, browserConfig];
I would have thought adding util to resolve.fallback would have fixed the issue, but I guess not?
I also tried using node-polyfill-webpack-plugin, but it didn't work, and it made a big fuss about esModuleInterop.
Permalink to my GitHub repo for full context. If you are interested in running the code yourself:
- Clone the repo
- Run
npm ci - Go to Run & Debug in VS Code and select the
Run Web Extensionconfiguration - Open the command palette and run
OpenSCAD: Open Cheatsheetcommand.
I know very little about Webpack besides that it is very confusing. Can anyone please provide any guidance?
Solution
Turns out, there is no need to polyfill TextDecoder, because it is part of globals for Node 16 and modern browsers. The import statement below can be removed, and everything works fine.
// import { TextDecoder } from 'util'; // <-- REMOVE ME
// ...
const htmlDocument = await vscode.workspace.fs
.readFile(
vscode.Uri.joinPath(this._cheatsheetUri, 'cheatsheet.html')
)
.then((uint8array) => {
const fileContent = new TextDecoder().decode(uint8array);
return parse(fileContent.toString());
});
See: https://github.com/microsoft/vscode-discussions/discussions/165#discussioncomment-3880268
Answered By - Antyos
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.