带有 webpack 的 VS Code 扩展并链接到 node_modules

问题描述 投票:0回答:1

我创建了一个使用 Webview 的 VS Code 扩展。在 Webview 中,我有一个指向

node_modules
文件夹中文件的链接,我按照各种来源的建议将其添加到 html 中(例如 vscode-codicons-sample):

const codiconsUri = webview.asWebviewUri(
  Uri.joinPath(this.context.extensionUri, 'node_modules', '@vscode/codicons', 'dist', 'codicon.css')
);

在 html 中:

<link href="${codiconsUri}" rel="stylesheet" />

现在我想使用 webpack 进行捆绑。我按照 Visual Studio Code here 中的说明进行操作。

.vscodeignore
文件中,我按照指示排除
node_modules
文件夹。 (这就是捆绑的主要原因)

当我现在打包项目时,当然,.vsix 文件中不存在

node_modules
,因此 Uri 无效。

你会如何解决这个问题? (我使用这种方法除了代码图标之外还插入了更多链接)

提前致谢!

visual-studio visual-studio-code webpack webview vscode-extensions
1个回答
0
投票

我决定采纳@MikeLischke的建议,将所需的文件复制到打包的

dist
文件夹中。但我不想手动执行此操作,所以我执行了以下操作。

节点模块访问器

首先,我创建了一个类,用于在

node_modules
文件夹中的文件与打包的
dist
文件夹中的目标之间进行映射。

import { NodeModulesKeys } from './nodeModulesKeys';
import { NodeModulesValue } from './nodeModulesValue';

export class NodeModulesAccessor {
  static readonly outputPath = 'dist';

  private static readonly pathMapping = new Map<NodeModulesKeys, NodeModulesValue>([
    [
      NodeModulesKeys.ffmpegMinJs,
      {
        sourcePath: ['node_modules', '@ffmpeg', 'ffmpeg', 'dist'],
        destinationPath: ['libs', '@ffmpeg', 'ffmpeg', 'dist'],
        fileName: 'ffmpeg.min.js',
      },
    ],
    [
      NodeModulesKeys.ffmpegCoreJs,
      {
        sourcePath: ['node_modules', '@ffmpeg', 'core', 'dist'],
        destinationPath: ['libs', '@ffmpeg', 'core', 'dist'],
        fileName: 'ffmpeg-core.js',
        includeFolder: true,
      },
    ],
    [
      NodeModulesKeys.codiconCss,
      {
        sourcePath: ['node_modules', '@vscode', 'codicons', 'dist'],
        destinationPath: ['libs', '@vscode', 'codicons', 'dist'],
        fileName: 'codicon.css',
        includeFolder: true,
      },
    ],
  ]);

  static getPathToOutputFile(key: NodeModulesKeys): string[] {
    const path = this.getMappedValue(key);
    return [this.outputPath, ...path.destinationPath, path.fileName];
  }

  static getPathToNodeModulesFile(key: NodeModulesKeys): NodeModulesValue {
    return this.getMappedValue(key);
  }

  private static getMappedValue(key: NodeModulesKeys): NodeModulesValue {
    const value = this.pathMapping.get(key);
    if (!value) {
      throw Error(`Path to "${key}" is not mapped.`);
    }
    return value;
  }
}

NodeModulesKeys
是我想要使用的所有文件的简单枚举:

export enum NodeModulesKeys {
  ffmpegMinJs,
  ffmpegCoreJs,
  codiconCss,
}

NodeModulesValue
是一个接口:

export interface NodeModulesValue {
  sourcePath: string[];
  destinationPath: string[];
  fileName: string;
  includeFolder?: boolean;
}

某些库(例如 codicons)需要文件夹内有多个文件。这就是为什么

NodeModulesValue
有一个可选字段
includeFolder

webpack.config.ts

这就是奇迹发生的地方(别担心,没那么复杂)。

您可以使用 CopyWebpackPlugin 在捆绑时复制文件:

import * as path from 'path';
import { NodeModulesAccessor } from './src/node-modules-accessor/nodeModulesAccessor';
import { NodeModulesKeys } from './src/node-modules-accessor/nodeModulesKeys';
import { Configuration } from 'webpack';
import CopyPlugin = require('copy-webpack-plugin');

const config: Configuration = {
  // omitted, nothing special here
  plugins: [copyNodeModulesFiles()],
};

function copyNodeModulesFiles(): CopyPlugin {
  const files: NodeModulesKeys[] = Object.keys(NodeModulesKeys)
    .filter((key) => !isNaN(Number(key)))
    .map((key) => Number(key));
  const copies: CopyPlugin.ObjectPattern[] = files.map((file) => {
    const value = NodeModulesAccessor.getPathToNodeModulesFile(file);
    let sourcePath;
    let destinationPath;
    if (value.includeFolder) {
      sourcePath = path.join(...value.sourcePath);
      destinationPath = path.join(...value.destinationPath);
    } else {
      sourcePath = path.join(...value.sourcePath, value.fileName);
      destinationPath = path.join(...value.destinationPath, value.fileName);
    }
    return {
      from: sourcePath,
      to: destinationPath,
    };
  });
  return new CopyPlugin({
    patterns: copies,
  });
}

module.exports = config;

这里我们迭代

NodeModulesKeys
枚举的所有值。 (如何迭代枚举值)并为每个值添加复制指令。

如果需要,我们还可以复制整个文件夹。

Webview 集成

为了获取 Uris 并在 webview html 中使用它们,我们再次使用

NodeModulesAccessor

const codiconsUri = webview.asWebviewUri(
  Uri.joinPath(this.context.extensionUri, ...NodeModulesAccessor.getPathToOutputFile(NodeModulesKeys.codiconCss))
);

重要

为了使 webview 能够访问

dist/libs
目录,您在创建 webview 时已将该目录定义为
localResourceRoot

this.viewPanel = window.createWebviewPanel('sampleId', 'Sample Webview', ViewColumn.Beside, {
  enableScripts: true,
  retainContextWhenHidden: true,
  localResourceRoots: [
    Uri.joinPath(this.context.extensionUri, NodeModulesAccessor.outputPath, 'libs'), // <--- Important
    Uri.joinPath(this.context.extensionUri, 'media'),
  ],
});

我希望这对其他人有用。

© www.soinside.com 2019 - 2024. All rights reserved.