Я пытаюсь использовать веб-пакет в проекте Typescript, который импортирует библиотеку веб-сборки, созданную emscripten. Все это выполняется внутри настраиваемого визуального элемента Power BI, что делает все еще более увлекательным. Я думаю, что это слишком сложно из-за контекста Power BI, TypeScript и WebAssembly, но на данный момент кажется, что это может быть просто проблема с веб-пакетом.
У меня есть проблема с путями, но я новичок в webpack и немного заблудился. Компиляция работает, но визуальный элемент выдает ошибку ChunkLoadError для фрагмента 1. (Есть два фрагмента.) Вещи, которые могут иметь значение, а могут и не иметь:
- Я могу указать в браузере "https://localhost:8080/assets/1.js "(или ... 0.js) нормально.
- Я обнаружил, что (я думаю), поскольку Power BI помещает мой код в iframe, изначально URL-адрес запроса, который пытался выполнить веб-пакет, был "https://app.powerbi.com/13.0.11428.218/assets/0.js". Это вызвало свойство baseUri в сгенерированном им теге скрипта. Изменение
output[publicPath]
на «https://localhost:8080/assets/» позволило браузеру загрузить фрагменты ( Я вижу, что они успешно входят в инструменты разработчика браузера), но webpack все еще жалуется. - Пробовал сдуть node_modules и переустановить. Никаких кубиков.
После вышесказанного вот как выглядит ошибка:
VM1292:119 Uncaught (in promise) ChunkLoadError: Loading chunk 1 failed.
(missing: https://localhost:8080/assets/1.js)
at Function.requireEnsure [as e] (<anonymous>:119:26)
at new Visual (<anonymous>:23155:79)
at r.create [as creator] (<anonymous>:237:14)
at r.init (https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:20:6200)
at https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:20:14488
at t.executeSafely (https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:20:18033)
at t.init (https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:20:14439)
at i.init (https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:21:35819)
at i.executeMessage (https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:21:42074)
at i.onMessageReceived (https://app.powerbi.com/13.0.11499.187/scripts/customVisualsHost.bundle.min.js:21:41772)
Если я остановлюсь на исключении, я окажусь здесь:
/******/ var error = new Error();
/******/ onScriptComplete = function (event) {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var chunk = installedChunks[chunkId];
/******/ if(chunk !== 0) {
/******/ if(chunk) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ ----> chunk[1](error);
/******/ }
/******/ installedChunks[chunkId] = undefined;
/******/ }
/******/ };
«Приостановлено из-за отклонения обещания» Но, увы, я действительно не знаю, на что я смотрю или для чего.
Вот мой webpack.config.js:
const path = require("path");
const fs = require("fs");
const webpack = require("webpack");
console.log(require.resolve("powerbi-visuals-webpack-plugin"));
const PowerBICustomVisualsWebpackPlugin = require("powerbi-visuals-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const Visualizer = require("webpack-visualizer-plugin");
const ExtraWatchWebpackPlugin = require("extra-watch-webpack-plugin");
// api configuration
const powerbiApi = require("powerbi-visuals-api");
// visual configuration json path
const pbivizPath = "./pbiviz.json";
const pbivizFile = require(path.join(__dirname, pbivizPath));
// the visual capabilities content
const capabilitiesPath = "./capabilities.json";
const capabilitiesFile = require(path.join(__dirname, capabilitiesPath));
const pluginLocation = "./.tmp/precompile/visualPlugin.ts"; // path to visual plugin file, the file generates by the plugin
// string resources
// const resourcesFolder = path.join(".", "stringResources");
// const localizationFolders = fs.readdirSync(resourcesFolder);
const localizationFolders = [];
const resourcesFolder = ".";
// babel options to support IE11
const babelOptions = {
presets: [
[
require.resolve("@babel/preset-env"),
{
targets: {
ie: "11",
},
useBuiltIns: "entry",
modules: false,
corejs: "3",
},
],
],
sourceType: "unambiguous", // Tell babel that the project can contain different module types, not only es2015 modules.
cacheDirectory: path.join(".tmp", "babelCache"),
};
module.exports = {
entry: {
"visual.js": pluginLocation,
},
target: "web",
node: {
fs: "empty",
},
optimization: {
concatenateModules: false,
// minimize: true, // enable minimization for create *.pbiviz file less than 2 Mb, can be disabled for dev mode
},
devtool: "source-map",
mode: "development",
module: {
rules: [
{
parser: {
amd: false,
},
},
{
test: /(\.ts)x|\.ts$/,
include: /powerbi-visuals-|src|precompile\\visualPlugin.ts/,
use: [
{
loader: require.resolve("babel-loader"),
options: babelOptions,
},
{
loader: require.resolve("ts-loader"),
options: {
transpileOnly: false,
experimentalWatchApi: false,
},
},
],
},
{
test: /(\.js)x|\.js$/,
use: [
{
loader: require.resolve("babel-loader"),
options: babelOptions,
},
],
},
{
test: /\.json$/,
loader: require.resolve("json-loader"),
type: "javascript/auto",
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: require.resolve("css-loader"),
},
{
loader: require.resolve("less-loader"),
options: {
paths: [path.resolve(__dirname, "..", "node_modules")],
},
},
],
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: require.resolve("css-loader"),
},
],
},
{
test: /\.(woff|ttf|ico|woff2|jpg|jpeg|png|webp)$/i,
use: [
{
loader: "base64-inline-loader",
},
],
},
],
},
resolve: {
extensions: [".wasm", ".tsx", ".ts", ".jsx", ".js", ".css"],
},
output: {
path: path.join(__dirname, "/.tmp", "drop"),
publicPath: "https://localhost:8080/assets/",
chunkFilename: "[name].js",
filename: "[name]",
},
devServer: {
disableHostCheck: true,
contentBase: path.join(__dirname, ".tmp", "drop"), // path with assets for dev server, they are generated by webpack plugin
compress: true,
port: 8080, // dev server port
publicPath: "https://localhost:8080/assets/",
hot: false,
inline: false,
// cert files for dev server
https: {
pfx: fs.readFileSync(path.join(__dirname, "node_modules/powerbi-visuals-tools/certs/PowerBICustomVisualTest_public.pfx")), // for windows
passphrase: "##########",
},
headers: {
"access-control-allow-origin": "*",
"cache-control": "public, max-age=0",
},
},
externals: {
"powerbi-visuals-api": "null",
fakeDefine: "false",
corePowerbiObject: "Function('return this.powerbi')()",
realWindow: "Function('return this')()",
},
plugins: [
new MiniCssExtractPlugin({
filename: "visual.css",
chunkFilename: "[id].css",
}),
new Visualizer({
filename: "webpack.statistics.dev.html",
}),
// visual plugin regenerates with the visual source, but it does not require relaunching dev server
new webpack.WatchIgnorePlugin([
path.join(__dirname, pluginLocation),
"./.tmp/**/*.*",
]),
// custom visuals plugin instance with options
new PowerBICustomVisualsWebpackPlugin({
...pbivizFile,
capabilities: capabilitiesFile,
stringResources: localizationFolders.map((localization) => path.join(
resourcesFolder,
localization,
"resources.resjson",
)),
apiVersion: powerbiApi.version,
capabilitiesSchema: powerbiApi.schemas.capabilities,
pbivizSchema: powerbiApi.schemas.pbiviz,
stringResourcesSchema: powerbiApi.schemas.stringResources,
dependenciesSchema: powerbiApi.schemas.dependencies,
devMode: true,
generatePbiviz: false,
generateResources: true,
modules: true,
visualSourceLocation: "../../src/visual",
pluginLocation,
packageOutPath: path.join(__dirname, "dist"),
}),
new ExtraWatchWebpackPlugin({
files: [
pbivizPath,
capabilitiesPath,
],
dirs: [
"assets",
],
}),
new webpack.ProvidePlugin({
window: "realWindow",
define: "fakeDefine",
powerbi: "corePowerbiObject",
}),
],
};