powerbi-visuals-tools 4.3.3 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Changelog.md +10 -0
- package/README.md +1 -1
- package/bin/pbiviz.js +55 -36
- package/certs/PowerBICustomVisualTest_private.key +26 -26
- package/certs/PowerBICustomVisualTest_public.crt +17 -17
- package/config.json +27 -34
- package/lib/CertificateTools.js +119 -143
- package/lib/CommandManager.js +52 -0
- package/lib/ConsoleWriter.js +63 -85
- package/lib/TemplateFetcher.js +23 -30
- package/lib/VisualGenerator.js +42 -56
- package/lib/VisualManager.js +193 -0
- package/lib/WebPackWrap.js +96 -145
- package/lib/utils.js +20 -13
- package/lib/webpack.config.js +48 -56
- package/package.json +21 -13
- package/spec/clean-tests.js +1 -1
- package/spec/e2e/pbivizCertSpec.js +14 -13
- package/spec/e2e/pbivizInfoSpec.js +7 -10
- package/spec/e2e/pbivizNewSpec.js +53 -65
- package/spec/e2e/pbivizPackageSpec.js +86 -90
- package/spec/e2e/pbivizStartSpec.js +6 -7
- package/spec/e2e/pbivizWebpackVerSpec.js +14 -16
- package/spec/e2e/{utils.js → testUtils.js} +9 -12
- package/spec/helpers/FileSystem.js +18 -18
- package/spec/jasmine-runner.js +5 -5
- package/src/CertificateTools.ts +431 -0
- package/src/CommandManager.ts +78 -0
- package/src/ConsoleWriter.ts +206 -0
- package/src/TemplateFetcher.ts +122 -0
- package/src/VisualGenerator.ts +236 -0
- package/src/VisualManager.ts +220 -0
- package/src/WebPackWrap.ts +299 -0
- package/src/utils.ts +40 -0
- package/src/webpack.config.ts +145 -0
- package/templates/pbiviz-json-template.js +2 -2
- package/templates/pbiviz.json.template +1 -1
- package/templates/plugin-ts-template.js +1 -1
- package/templates/visuals/default/.eslintignore +5 -0
- package/templates/visuals/default/.eslintrc.js +20 -0
- package/templates/visuals/default/package.json +9 -8
- package/templates/visuals/default/pbiviz.json +3 -2
- package/templates/visuals/default/tsconfig.json +2 -2
- package/templates/visuals/rhtml/.eslintignore +5 -0
- package/templates/visuals/rhtml/.eslintrc.js +20 -0
- package/templates/visuals/rhtml/package.json +7 -6
- package/templates/visuals/rhtml/pbiviz.json +2 -1
- package/templates/visuals/rvisual/.eslintignore +5 -0
- package/templates/visuals/rvisual/.eslintrc.js +20 -0
- package/templates/visuals/rvisual/package.json +5 -4
- package/templates/visuals/slicer/.eslintignore +5 -0
- package/templates/visuals/slicer/.eslintrc.js +20 -0
- package/templates/visuals/slicer/package.json +8 -7
- package/templates/visuals/table/.eslintignore +5 -0
- package/templates/visuals/table/.eslintrc.js +20 -0
- package/templates/visuals/table/package.json +8 -7
- package/templates/visuals/table/tsconfig.json +4 -0
- package/tsconfig.json +22 -0
- package/bin/pbiviz-info.js +0 -54
- package/bin/pbiviz-new.js +0 -82
- package/bin/pbiviz-package.js +0 -122
- package/bin/pbiviz-start.js +0 -142
- package/lib/CommandHelpManager.js +0 -51
- package/lib/VisualPackage.js +0 -118
- package/templates/visuals/default/tslint.json +0 -9
- package/templates/visuals/rhtml/tslint.json +0 -9
- package/templates/visuals/rvisual/tslint.json +0 -9
- package/templates/visuals/slicer/tslint.json +0 -9
- package/templates/visuals/table/tslint.json +0 -9
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Power BI Visual CLI
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Microsoft Corporation
|
|
5
|
+
* All rights reserved.
|
|
6
|
+
* MIT License
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the ""Software""), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in
|
|
16
|
+
* all copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
24
|
+
* THE SOFTWARE.
|
|
25
|
+
*/
|
|
26
|
+
"use strict";
|
|
27
|
+
import webpack from "webpack";
|
|
28
|
+
import WebpackDevServer from "webpack-dev-server";
|
|
29
|
+
import childProcess from 'child_process';
|
|
30
|
+
import fs from 'fs-extra';
|
|
31
|
+
import path from 'path';
|
|
32
|
+
import ConsoleWriter from './ConsoleWriter.js';
|
|
33
|
+
import VisualGenerator from './VisualGenerator.js';
|
|
34
|
+
import { readJsonFromRoot, readJsonFromVisual } from './utils.js';
|
|
35
|
+
import WebpackWrap from './WebPackWrap.js';
|
|
36
|
+
import TemplateFetcher from "./TemplateFetcher.js";
|
|
37
|
+
const PBIVIZ_FILE = 'pbiviz.json';
|
|
38
|
+
/**
|
|
39
|
+
* Represents an instance of a visual package based on file path
|
|
40
|
+
*/
|
|
41
|
+
export default class VisualManager {
|
|
42
|
+
basePath;
|
|
43
|
+
pbivizConfig;
|
|
44
|
+
webpackConfig;
|
|
45
|
+
compiler;
|
|
46
|
+
webpackDevServer;
|
|
47
|
+
constructor(rootPath) {
|
|
48
|
+
this.basePath = rootPath;
|
|
49
|
+
}
|
|
50
|
+
prepareVisual() {
|
|
51
|
+
if (this.doesPBIVIZExists()) {
|
|
52
|
+
this.pbivizConfig = readJsonFromVisual(PBIVIZ_FILE, this.basePath);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
throw new Error(PBIVIZ_FILE + ' not found. You must be in the root of a visual project to run this command.');
|
|
56
|
+
}
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
async initializeWebpack(webpackOptions) {
|
|
60
|
+
const webpackWrap = new WebpackWrap();
|
|
61
|
+
this.webpackConfig = await webpackWrap.generateWebpackConfig(this, webpackOptions);
|
|
62
|
+
this.compiler = webpack(this.webpackConfig);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
generatePackage() {
|
|
66
|
+
const callback = (err, stats) => {
|
|
67
|
+
this.parseCompilationResults(err, stats);
|
|
68
|
+
};
|
|
69
|
+
this.compiler.run(callback);
|
|
70
|
+
}
|
|
71
|
+
startWebpackServer(generateDropFiles = false) {
|
|
72
|
+
ConsoleWriter.blank();
|
|
73
|
+
ConsoleWriter.info('Starting server...');
|
|
74
|
+
try {
|
|
75
|
+
if (generateDropFiles) {
|
|
76
|
+
this.prepareDropFiles();
|
|
77
|
+
}
|
|
78
|
+
this.webpackDevServer = new WebpackDevServer({
|
|
79
|
+
...this.webpackConfig.devServer,
|
|
80
|
+
client: false,
|
|
81
|
+
hot: false,
|
|
82
|
+
devMiddleware: {
|
|
83
|
+
writeToDisk: true
|
|
84
|
+
}
|
|
85
|
+
}, this.compiler);
|
|
86
|
+
(async () => {
|
|
87
|
+
await this.webpackDevServer.start();
|
|
88
|
+
ConsoleWriter.info(`Server listening on port ${this.webpackConfig.devServer.port}`);
|
|
89
|
+
})();
|
|
90
|
+
process.on('SIGINT', this.stopServer);
|
|
91
|
+
process.on('SIGTERM', this.stopServer);
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
ConsoleWriter.error(e.message);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
displayInfo() {
|
|
99
|
+
if (this.pbivizConfig) {
|
|
100
|
+
ConsoleWriter.infoTable(this.pbivizConfig);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
ConsoleWriter.error('Unable to load visual info. Please ensure the package is valid.');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Creates a new visual package
|
|
108
|
+
*/
|
|
109
|
+
static async createVisual(rootPath, visualName, generateOptions) {
|
|
110
|
+
ConsoleWriter.info('Creating new visual');
|
|
111
|
+
if (generateOptions.force) {
|
|
112
|
+
ConsoleWriter.warning('Running with force flag. Existing files will be overwritten');
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const config = readJsonFromRoot('config.json');
|
|
116
|
+
if (config.visualTemplates[generateOptions.template]) {
|
|
117
|
+
new TemplateFetcher(generateOptions.template, visualName, undefined)
|
|
118
|
+
.fetch();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const newVisualPath = await VisualGenerator.generateVisual(rootPath, visualName, generateOptions);
|
|
122
|
+
await VisualManager.installPackages(newVisualPath).then(() => ConsoleWriter.done('Visual creation complete'));
|
|
123
|
+
return new VisualManager(newVisualPath);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
ConsoleWriter.error(['Unable to create visual.\n', error]);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Install npm dependencies for visual
|
|
132
|
+
*/
|
|
133
|
+
static installPackages(visualPath) {
|
|
134
|
+
return new Promise(function (resolve, reject) {
|
|
135
|
+
ConsoleWriter.info('Installing packages...');
|
|
136
|
+
childProcess.exec(`npm install`, { cwd: visualPath }, (err) => {
|
|
137
|
+
if (err) {
|
|
138
|
+
reject(new Error('Package install failed.'));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
ConsoleWriter.info('Installed packages.');
|
|
142
|
+
resolve();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
doesPBIVIZExists() {
|
|
148
|
+
return fs.existsSync(PBIVIZ_FILE);
|
|
149
|
+
}
|
|
150
|
+
prepareDropFiles() {
|
|
151
|
+
this.webpackConfig.devServer.onBeforeSetupMiddleware = (devServer) => {
|
|
152
|
+
const { headers, publicPath, static: { directory } } = this.webpackConfig.devServer;
|
|
153
|
+
const assets = ['visual.js`', 'visual.css', 'pbiviz.json'];
|
|
154
|
+
const setHeaders = (res) => {
|
|
155
|
+
Object.getOwnPropertyNames(headers)
|
|
156
|
+
.forEach(property => res.header(property, headers[property]));
|
|
157
|
+
};
|
|
158
|
+
const readFile = (file, res) => {
|
|
159
|
+
fs.readFile(file).then(function (content) {
|
|
160
|
+
res.write(content);
|
|
161
|
+
res.end();
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
assets.forEach(asset => {
|
|
165
|
+
devServer.app.get(`${publicPath}/${asset}`, function (req, res) {
|
|
166
|
+
setHeaders(res);
|
|
167
|
+
readFile(path.join(directory, asset), res);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
stopServer() {
|
|
173
|
+
ConsoleWriter.blank();
|
|
174
|
+
ConsoleWriter.info("Stopping server...");
|
|
175
|
+
if (this.webpackDevServer) {
|
|
176
|
+
this.webpackDevServer.close();
|
|
177
|
+
this.webpackDevServer = null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
parseCompilationResults(err, stats) {
|
|
181
|
+
ConsoleWriter.blank();
|
|
182
|
+
if (err) {
|
|
183
|
+
ConsoleWriter.error(`Package wasn't created. ${JSON.stringify(err)}`);
|
|
184
|
+
}
|
|
185
|
+
if (stats?.compilation.errors.length) {
|
|
186
|
+
stats.compilation.errors.forEach(error => ConsoleWriter.error(error.message));
|
|
187
|
+
ConsoleWriter.error(`Package wasn't created. ${stats.compilation.errors.length} errors found.`);
|
|
188
|
+
}
|
|
189
|
+
if (!err && !stats?.compilation.errors.length) {
|
|
190
|
+
ConsoleWriter.done('Build completed successfully');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
package/lib/WebPackWrap.js
CHANGED
|
@@ -1,60 +1,57 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import webpack from 'webpack';
|
|
6
|
+
import util from 'util';
|
|
7
|
+
const exec = util.promisify(processExec);
|
|
8
|
+
import { exec as processExec } from 'child_process';
|
|
9
|
+
import lodashCloneDeep from 'lodash.clonedeep';
|
|
10
|
+
import ExtraWatchWebpackPlugin from 'extra-watch-webpack-plugin';
|
|
11
|
+
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
|
12
|
+
import { PowerBICustomVisualsWebpackPlugin } from 'powerbi-visuals-webpack-plugin';
|
|
13
|
+
import ConsoleWriter from './ConsoleWriter.js';
|
|
14
|
+
import { resolveCertificate } from "./CertificateTools.js";
|
|
15
|
+
import { getRootPath, readJsonFromRoot, readJsonFromVisual } from './utils.js';
|
|
16
|
+
const config = readJsonFromRoot('config.json');
|
|
17
|
+
const npmPackage = readJsonFromRoot('package.json');
|
|
16
18
|
const visualPlugin = "visualPlugin.ts";
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const encoding = "utf8";
|
|
20
|
+
export default class WebPackWrap {
|
|
21
|
+
pbiviz;
|
|
22
|
+
webpackConfig;
|
|
22
23
|
static async prepareFoldersAndFiles(visualPackage) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const tmpFolder = path.join(visualPackage.basePath, ".tmp");
|
|
25
|
+
const precompileFolder = path.join(visualPackage.basePath, config.build.precompileFolder);
|
|
26
|
+
const dropFolder = path.join(visualPackage.basePath, config.build.dropFolder);
|
|
27
|
+
const packageDropFolder = path.join(visualPackage.basePath, config.package.dropFolder);
|
|
28
|
+
const visualPluginFile = path.join(visualPackage.basePath, config.build.precompileFolder, visualPlugin);
|
|
28
29
|
await fs.ensureDir(tmpFolder);
|
|
29
30
|
await fs.ensureDir(precompileFolder);
|
|
30
31
|
await fs.ensureDir(dropFolder);
|
|
31
|
-
await fs.ensureDir(
|
|
32
|
+
await fs.ensureDir(packageDropFolder);
|
|
32
33
|
await fs.createFile(visualPluginFile);
|
|
33
34
|
}
|
|
34
|
-
|
|
35
35
|
static loadAPIPackage() {
|
|
36
36
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return require(basePath);
|
|
41
|
-
} catch (ex) {
|
|
37
|
+
return import("file://" + path.join(process.cwd(), "node_modules", "powerbi-visuals-api", "index.js"));
|
|
38
|
+
}
|
|
39
|
+
catch (ex) {
|
|
42
40
|
return null;
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
|
-
|
|
46
43
|
async installAPIpackage() {
|
|
47
|
-
|
|
44
|
+
const apiVersion = this.pbiviz.apiVersion ? `~${this.pbiviz.apiVersion}` : "latest";
|
|
48
45
|
try {
|
|
49
46
|
ConsoleWriter.info(`Installing API: ${apiVersion}...`);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ConsoleWriter.warn(stderr);
|
|
47
|
+
const { stdout, stderr } = await exec(`npm install --save powerbi-visuals-api@${apiVersion}`);
|
|
48
|
+
if (stdout)
|
|
49
|
+
ConsoleWriter.info(stdout);
|
|
50
|
+
if (stderr)
|
|
51
|
+
ConsoleWriter.warning(stderr);
|
|
56
52
|
return true;
|
|
57
|
-
}
|
|
53
|
+
}
|
|
54
|
+
catch (ex) {
|
|
58
55
|
if (ex.message.indexOf("No matching version found for powerbi-visuals-api") !== -1) {
|
|
59
56
|
throw new Error(`Error: Invalid API version: ${apiVersion}`);
|
|
60
57
|
}
|
|
@@ -62,7 +59,6 @@ class WebPackGenerator {
|
|
|
62
59
|
return false;
|
|
63
60
|
}
|
|
64
61
|
}
|
|
65
|
-
|
|
66
62
|
enableOptimization() {
|
|
67
63
|
this.webpackConfig.mode = "production";
|
|
68
64
|
this.webpackConfig.optimization = {
|
|
@@ -70,14 +66,12 @@ class WebPackGenerator {
|
|
|
70
66
|
minimize: true
|
|
71
67
|
};
|
|
72
68
|
}
|
|
73
|
-
|
|
74
69
|
async configureDevServer(visualPackage, port = 8080) {
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
const options = await resolveCertificate();
|
|
77
71
|
this.webpackConfig.devServer = {
|
|
78
72
|
...this.webpackConfig.devServer,
|
|
79
73
|
hot: false,
|
|
80
|
-
port
|
|
74
|
+
port,
|
|
81
75
|
static: {
|
|
82
76
|
directory: path.join(visualPackage.basePath, config.build.dropFolder),
|
|
83
77
|
publicPath: config.server.assetsRoute
|
|
@@ -93,65 +87,60 @@ class WebPackGenerator {
|
|
|
93
87
|
}
|
|
94
88
|
};
|
|
95
89
|
}
|
|
96
|
-
|
|
97
90
|
configureVisualPlugin(options, tsconfig, visualPackage) {
|
|
98
|
-
const visualJSFilePath =
|
|
91
|
+
const visualJSFilePath = tsconfig.compilerOptions.out || tsconfig.compilerOptions.outDir;
|
|
99
92
|
this.webpackConfig.output.path = path.join(visualPackage.basePath, config.build.dropFolder);
|
|
100
93
|
this.webpackConfig.output.filename = "[name]";
|
|
101
|
-
|
|
102
|
-
this.webpackConfig.
|
|
103
|
-
new webpack.WatchIgnorePlugin({ paths: [visualPluginPath] })
|
|
104
|
-
);
|
|
94
|
+
const visualPluginPath = path.join(process.cwd(), config.build.precompileFolder, visualPlugin);
|
|
95
|
+
this.webpackConfig.watchOptions.ignored.push(visualPluginPath);
|
|
105
96
|
if (tsconfig.compilerOptions.out) {
|
|
106
97
|
this.webpackConfig.entry = {
|
|
107
98
|
"visual.js": visualJSFilePath
|
|
108
99
|
};
|
|
109
|
-
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
110
102
|
this.webpackConfig.entry["visual.js"] = [visualPluginPath];
|
|
111
103
|
this.webpackConfig.output.library = `${this.pbiviz.visual.guid}${options.devMode ? "_DEBUG" : ""}`;
|
|
112
104
|
this.webpackConfig.output.libraryTarget = 'var';
|
|
113
105
|
}
|
|
114
106
|
}
|
|
115
|
-
|
|
116
107
|
async getEnvironmentDetails() {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
108
|
+
const env = {
|
|
109
|
+
nodeVersion: process.versions.node,
|
|
110
|
+
osPlatform: await os.platform(),
|
|
111
|
+
osVersion: await os.version ?? "undefined",
|
|
112
|
+
osReleaseVersion: await os.release(),
|
|
113
|
+
toolsVersion: npmPackage.version
|
|
114
|
+
};
|
|
123
115
|
return env;
|
|
124
116
|
}
|
|
125
|
-
|
|
126
117
|
async configureCustomVisualsWebpackPlugin(visualPackage, options, tsconfig) {
|
|
127
|
-
|
|
118
|
+
const pluginConfiguration = lodashCloneDeep(visualPackage.pbivizConfig);
|
|
128
119
|
//(?=\D*$) - positive look-ahead to find last version symbols and exclude any non-digit symbols after the version.
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
const regexFullVersion = /(?:\d+\.?){1,3}(?=\D*$)/;
|
|
121
|
+
const regexMinorVersion = /\d+(?:\.\d+)?/;
|
|
131
122
|
let apiVersionInstalled;
|
|
132
123
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
124
|
+
const subprocess = await exec('npm list powerbi-visuals-api version');
|
|
125
|
+
apiVersionInstalled = subprocess.stdout.match(regexFullVersion)[0];
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
ConsoleWriter.warning(`"powerbi-visuals-api" is not installed`);
|
|
136
129
|
}
|
|
137
130
|
// if the powerbi-visual-api package wasn't installed
|
|
138
131
|
// install the powerbi-visual-api, with version from apiVersion in pbiviz.json
|
|
139
132
|
// or the latest API, if apiVersion is absent in pbiviz.json
|
|
140
|
-
if (!apiVersionInstalled ||
|
|
141
|
-
ConsoleWriter.
|
|
133
|
+
if (!apiVersionInstalled || !this.pbiviz.apiVersion || this.pbiviz.apiVersion.match(regexMinorVersion)[0] != apiVersionInstalled.match(regexMinorVersion)[0]) {
|
|
134
|
+
ConsoleWriter.warning(`installed "powerbi-visuals-api" version - "${apiVersionInstalled}", is not match with the version specified in pbviz.json - "${this.pbiviz.apiVersion}".`);
|
|
142
135
|
await this.installAPIpackage();
|
|
143
136
|
}
|
|
144
|
-
|
|
145
137
|
// pluginConfiguration.env = await this.getEnvironmentDetails();
|
|
146
|
-
|
|
147
|
-
let api = WebPackGenerator.loadAPIPackage(visualPackage);
|
|
138
|
+
const api = await WebPackWrap.loadAPIPackage();
|
|
148
139
|
pluginConfiguration.apiVersion = api.version;
|
|
149
140
|
pluginConfiguration.capabilitiesSchema = api.schemas.capabilities;
|
|
150
141
|
pluginConfiguration.pbivizSchema = api.schemas.pbiviz;
|
|
151
142
|
pluginConfiguration.stringResourcesSchema = api.schemas.stringResources;
|
|
152
143
|
pluginConfiguration.dependenciesSchema = api.schemas.dependencies;
|
|
153
|
-
|
|
154
|
-
|
|
155
144
|
pluginConfiguration.customVisualID = `CustomVisual_${this.pbiviz.visual.guid}`.replace(/[^\w\s]/gi, '');
|
|
156
145
|
pluginConfiguration.devMode = (typeof options.devMode === "undefined") ? true : options.devMode;
|
|
157
146
|
pluginConfiguration.generatePbiviz = options.generatePbiviz;
|
|
@@ -165,49 +154,30 @@ class WebPackGenerator {
|
|
|
165
154
|
pluginConfiguration.compression = options.compression;
|
|
166
155
|
return pluginConfiguration;
|
|
167
156
|
}
|
|
168
|
-
|
|
169
157
|
async appendPlugins(options, visualPackage, tsconfig) {
|
|
170
|
-
|
|
171
|
-
|
|
158
|
+
const pluginConfiguration = await this.configureCustomVisualsWebpackPlugin(visualPackage, options, tsconfig);
|
|
172
159
|
let statsFilename = config.build.stats.split("/").pop();
|
|
173
|
-
|
|
174
|
-
statsFilename = statsFilename
|
|
160
|
+
const statsLocation = config.build.stats.split("/").slice(0, -1).join(path.sep);
|
|
161
|
+
statsFilename = statsFilename?.split(".").slice(0, -1).join(".");
|
|
175
162
|
statsFilename = `${statsFilename}.${options.devMode ? "dev" : "prod"}.html`;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
analyzerMode: `static`
|
|
183
|
-
})
|
|
184
|
-
);
|
|
163
|
+
if (options.stats) {
|
|
164
|
+
this.webpackConfig.plugins.push(new BundleAnalyzerPlugin({
|
|
165
|
+
reportFilename: path.join(statsLocation, statsFilename),
|
|
166
|
+
openAnalyzer: false,
|
|
167
|
+
analyzerMode: `static`
|
|
168
|
+
}));
|
|
185
169
|
}
|
|
186
|
-
this.webpackConfig.plugins.push(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
files: [visualPackage.buildPath(this.pbiviz.capabilities)]
|
|
190
|
-
}),
|
|
191
|
-
new webpack.ProvidePlugin({
|
|
192
|
-
window: 'realWindow',
|
|
193
|
-
define: 'fakeDefine',
|
|
194
|
-
powerbi: 'globalPowerbi'
|
|
195
|
-
})
|
|
196
|
-
);
|
|
197
|
-
|
|
170
|
+
this.webpackConfig.plugins.push(new PowerBICustomVisualsWebpackPlugin(pluginConfiguration), new ExtraWatchWebpackPlugin({
|
|
171
|
+
files: this.pbiviz.capabilities
|
|
172
|
+
}));
|
|
198
173
|
if (options.devtool === "source-map" && this.webpackConfig.devServer.port) {
|
|
199
|
-
this.webpackConfig.plugins.push(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
})
|
|
204
|
-
);
|
|
174
|
+
this.webpackConfig.plugins.push(new webpack.SourceMapDevToolPlugin({
|
|
175
|
+
filename: '[file].map',
|
|
176
|
+
publicPath: `https://localhost:${this.webpackConfig.devServer.port}/assets/`
|
|
177
|
+
}));
|
|
205
178
|
}
|
|
206
179
|
}
|
|
207
|
-
|
|
208
|
-
useLoader({
|
|
209
|
-
fast = false
|
|
210
|
-
}) {
|
|
180
|
+
async useLoader({ fast = false }) {
|
|
211
181
|
let tsOptions = {};
|
|
212
182
|
if (fast) {
|
|
213
183
|
tsOptions = {
|
|
@@ -219,46 +189,37 @@ class WebPackGenerator {
|
|
|
219
189
|
test: /(\.ts)x?$/,
|
|
220
190
|
use: [
|
|
221
191
|
{
|
|
222
|
-
loader:
|
|
192
|
+
loader: path.resolve(getRootPath(), "node_modules", "ts-loader"),
|
|
223
193
|
options: tsOptions
|
|
224
194
|
}
|
|
225
195
|
]
|
|
226
196
|
});
|
|
227
197
|
}
|
|
228
|
-
|
|
229
198
|
async prepareWebPackConfig(visualPackage, options, tsconfig) {
|
|
230
|
-
this.webpackConfig =
|
|
199
|
+
this.webpackConfig = Object.assign({}, await import('./webpack.config.js')).default;
|
|
231
200
|
if (options.minifyJS) {
|
|
232
201
|
this.enableOptimization();
|
|
233
202
|
}
|
|
234
|
-
|
|
235
203
|
if (options.devtool) {
|
|
236
204
|
this.webpackConfig.devtool = options.devtool;
|
|
237
205
|
}
|
|
238
|
-
|
|
239
206
|
await this.appendPlugins(options, visualPackage, tsconfig);
|
|
240
207
|
await this.configureDevServer(visualPackage, options.devServerPort);
|
|
241
208
|
await this.configureVisualPlugin(options, tsconfig, visualPackage);
|
|
242
|
-
this.useLoader({
|
|
209
|
+
await this.useLoader({
|
|
243
210
|
fast: options.fast
|
|
244
211
|
});
|
|
245
|
-
|
|
246
212
|
return this.webpackConfig;
|
|
247
213
|
}
|
|
248
|
-
|
|
249
214
|
async assemblyExternalJSFiles(visualPackage) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
await fs.writeFile(
|
|
253
|
-
externalJSFilesPath,
|
|
254
|
-
externalJSFilesContent, {
|
|
215
|
+
const externalJSFilesContent = "";
|
|
216
|
+
const externalJSFilesPath = path.join(visualPackage.basePath, config.build.precompileFolder, "externalJS.js");
|
|
217
|
+
await fs.writeFile(externalJSFilesPath, externalJSFilesContent, {
|
|
255
218
|
encoding: encoding
|
|
256
219
|
});
|
|
257
|
-
|
|
258
220
|
return externalJSFilesPath;
|
|
259
221
|
}
|
|
260
|
-
|
|
261
|
-
async applyWebpackConfig(visualPackage, options = {
|
|
222
|
+
async generateWebpackConfig(visualPackage, options = {
|
|
262
223
|
devMode: false,
|
|
263
224
|
generateResources: false,
|
|
264
225
|
generatePbiviz: false,
|
|
@@ -267,27 +228,17 @@ class WebPackGenerator {
|
|
|
267
228
|
devServerPort: 8080,
|
|
268
229
|
fast: false,
|
|
269
230
|
compression: 0,
|
|
270
|
-
|
|
231
|
+
stats: true
|
|
271
232
|
}) {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
this.pbiviz = require(this.pbivizJsonPath);
|
|
277
|
-
|
|
278
|
-
const capabliliesPath = this.pbiviz.capabilities;
|
|
279
|
-
visualPackage.config.capabilities = capabliliesPath;
|
|
280
|
-
|
|
233
|
+
const tsconfig = readJsonFromVisual('tsconfig.json');
|
|
234
|
+
this.pbiviz = readJsonFromVisual('pbiviz.json');
|
|
235
|
+
const capabilitiesPath = this.pbiviz.capabilities;
|
|
236
|
+
visualPackage.pbivizConfig.capabilities = capabilitiesPath;
|
|
281
237
|
const dependenciesPath = this.pbiviz.dependencies && path.join(process.cwd(), this.pbiviz.dependencies);
|
|
282
|
-
const dependenciesFile = fs.existsSync(dependenciesPath) &&
|
|
283
|
-
visualPackage.
|
|
284
|
-
|
|
285
|
-
await
|
|
286
|
-
|
|
287
|
-
let webpackConfig = await this.prepareWebPackConfig(visualPackage, options, tsconfig);
|
|
288
|
-
|
|
289
|
-
return { webpackConfig };
|
|
238
|
+
const dependenciesFile = fs.existsSync(dependenciesPath) && JSON.parse(fs.readFileSync(dependenciesPath));
|
|
239
|
+
visualPackage.pbivizConfig.dependencies = typeof dependenciesFile === 'object' ? dependenciesFile : {};
|
|
240
|
+
await WebPackWrap.prepareFoldersAndFiles(visualPackage);
|
|
241
|
+
const webpackConfig = await this.prepareWebPackConfig(visualPackage, options, tsconfig);
|
|
242
|
+
return webpackConfig;
|
|
290
243
|
}
|
|
291
244
|
}
|
|
292
|
-
|
|
293
|
-
module.exports = WebPackGenerator;
|
package/lib/utils.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function download(url, pathToFile) {
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import https from "https";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
export function download(url, pathToFile) {
|
|
6
6
|
return new Promise((resolve, reject) => {
|
|
7
7
|
const fileStream = fs.createWriteStream(pathToFile);
|
|
8
8
|
https.get(url, (res) => {
|
|
@@ -13,14 +13,21 @@ function download(url, pathToFile) {
|
|
|
13
13
|
.on('error', (error) => reject(error));
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let folder = path.join("./", folderName);
|
|
16
|
+
export function createFolder(folderName) {
|
|
17
|
+
const folder = path.join("./", folderName);
|
|
19
18
|
fs.ensureDirSync(folder);
|
|
20
19
|
return folder;
|
|
21
20
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
export function getRootPath() {
|
|
22
|
+
const pathToDirectory = fileURLToPath(import.meta.url);
|
|
23
|
+
return path.join(pathToDirectory, "..", "..");
|
|
24
|
+
}
|
|
25
|
+
export function readFileFromRoot(filePath) {
|
|
26
|
+
return fs.readFileSync(path.join(getRootPath(), filePath), "utf8");
|
|
27
|
+
}
|
|
28
|
+
export function readJsonFromRoot(filePath) {
|
|
29
|
+
return JSON.parse(readFileFromRoot(filePath));
|
|
30
|
+
}
|
|
31
|
+
export function readJsonFromVisual(filePath, visualPath) {
|
|
32
|
+
return JSON.parse(fs.readFileSync(path.join(visualPath ?? process.cwd(), filePath), "utf8"));
|
|
33
|
+
}
|