@grafana/create-plugin 7.17.0 → 7.18.0
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 +12 -0
- package/dist/codemods/additions/additions.js +7 -0
- package/dist/codemods/additions/prompts/rspack.md +118 -0
- package/dist/codemods/additions/scripts/docs.js +2 -2
- package/dist/codemods/additions/scripts/rspack.js +322 -0
- package/dist/codemods/agentic/prompts.js +1 -1
- package/dist/codemods/migrations/migrations.js +6 -0
- package/dist/codemods/migrations/scripts/020-rename-rspack-feature-flag.js +8 -0
- package/dist/codemods/utils.rspack.js +38 -0
- package/dist/commands/generate.command.js +1 -9
- package/dist/constants.js +0 -1
- package/dist/utils/utils.templates.js +4 -4
- package/package.json +1 -1
- package/src/codemods/additions/additions.test.ts +9 -0
- package/src/codemods/additions/additions.ts +7 -0
- package/src/codemods/additions/prompts/rspack.md +118 -0
- package/src/codemods/additions/scripts/docs.test.ts +4 -4
- package/src/codemods/additions/scripts/docs.ts +2 -2
- package/src/codemods/additions/scripts/rspack.test.ts +768 -0
- package/src/codemods/additions/scripts/rspack.ts +428 -0
- package/src/codemods/agentic/prompts.test.ts +11 -2
- package/src/codemods/agentic/prompts.ts +1 -1
- package/src/codemods/migrations/migrations.ts +7 -0
- package/src/codemods/migrations/scripts/020-rename-rspack-feature-flag.test.ts +94 -0
- package/src/codemods/migrations/scripts/020-rename-rspack-feature-flag.ts +8 -0
- package/src/codemods/utils.rspack.ts +58 -0
- package/src/codemods/utils.test.ts +5 -2
- package/src/commands/generate.command.ts +2 -10
- package/src/constants.ts +0 -1
- package/src/types.ts +1 -1
- package/src/utils/tests/utils.config.test.ts +10 -0
- package/src/utils/utils.config.ts +2 -1
- package/src/utils/utils.templates.ts +4 -4
- package/templates/common/.config/AGENTS/instructions.md +2 -2
- package/templates/common/.config/README.md +56 -0
- package/templates/common/.config/bundler/externals.ts +2 -2
- package/templates/common/.config/rspack/DiagnosticsRspackPlugin.ts +29 -0
- package/templates/common/.config/rspack/LicenseRspackPlugin.ts +43 -0
- package/templates/common/.config/rspack/LiveReloadRspackPlugin.ts +95 -0
- package/templates/common/.config/rspack/rspack.config.ts +41 -32
- package/templates/common/.cprc.json +1 -2
- package/templates/common/_package.json +18 -18
- package/templates/common/.config/rspack/liveReloadPlugin.ts +0 -133
package/src/types.ts
CHANGED
|
@@ -44,6 +44,16 @@ describe('getConfig', () => {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
+
it('should not let cli args switch new plugins to rspack', async () => {
|
|
48
|
+
mocks.argv = {
|
|
49
|
+
'feature-flags': 'useRspack',
|
|
50
|
+
};
|
|
51
|
+
const config = getConfig(tmpDir);
|
|
52
|
+
|
|
53
|
+
expect(config.features).toEqual(DEFAULT_FEATURE_FLAGS);
|
|
54
|
+
expect(config.features).not.toHaveProperty('useRspack');
|
|
55
|
+
});
|
|
56
|
+
|
|
47
57
|
it('should override default feature flags via cli args', async () => {
|
|
48
58
|
mocks.argv = {
|
|
49
59
|
'feature-flags': 'bundleGrafanaUI',
|
|
@@ -11,7 +11,8 @@ import { EOL } from 'node:os';
|
|
|
11
11
|
|
|
12
12
|
export type FeatureFlags = {
|
|
13
13
|
bundleGrafanaUI?: boolean;
|
|
14
|
-
|
|
14
|
+
// set by `add rspack` in .config/.cprc.json. not a default flag, so --feature-flags cannot set it
|
|
15
|
+
useRspack?: boolean;
|
|
15
16
|
useExperimentalUpdates?: boolean;
|
|
16
17
|
};
|
|
17
18
|
|
|
@@ -123,8 +123,8 @@ export function buildTemplateData({
|
|
|
123
123
|
bundleGrafanaUI: features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI,
|
|
124
124
|
scenesVersion: '^8.17.0',
|
|
125
125
|
pluginExecutable: pluginJson.executable,
|
|
126
|
-
|
|
127
|
-
frontendBundler: features.
|
|
126
|
+
useRspack: Boolean(features.useRspack),
|
|
127
|
+
frontendBundler: features.useRspack ? 'rspack' : 'webpack',
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -140,7 +140,7 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
|
|
|
140
140
|
const { features } = getConfig();
|
|
141
141
|
const currentVersion = CURRENT_APP_VERSION;
|
|
142
142
|
const bundleGrafanaUI = features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI;
|
|
143
|
-
const frontendBundler = features.
|
|
143
|
+
const frontendBundler = features.useRspack ? 'rspack' : 'webpack';
|
|
144
144
|
|
|
145
145
|
let templateData: TemplateData;
|
|
146
146
|
|
|
@@ -164,7 +164,7 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
|
|
|
164
164
|
version: currentVersion,
|
|
165
165
|
bundleGrafanaUI,
|
|
166
166
|
scenesVersion: '^8.17.0',
|
|
167
|
-
|
|
167
|
+
useRspack: Boolean(features.useRspack),
|
|
168
168
|
frontendBundler,
|
|
169
169
|
};
|
|
170
170
|
// Updating or migrating a plugin
|
|
@@ -28,7 +28,7 @@ Your training data about the Grafana API is out of date. Use the official docume
|
|
|
28
28
|
- **Do not change plugin ID or plugin type** in `plugin.json`.
|
|
29
29
|
- Any modifications to `plugin.json` require a **restart of the Grafana server**. Remind the user of this.
|
|
30
30
|
- Use `secureJsonData` for credentials and secrets; use `jsonData` only for non-sensitive configuration.
|
|
31
|
-
- **You must use
|
|
31
|
+
- **You must use {{frontendBundler}}** with the configuration provided in `.config/` for frontend builds.
|
|
32
32
|
- **You must use mage** with the build targets provided by the Grafana plugin Go SDK for backend builds.
|
|
33
|
-
- To extend
|
|
33
|
+
- To extend {{frontendBundler}}, prettier, eslint or other tools, use the existing configuration as a base. Follow the guide: https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations.md
|
|
34
34
|
- Use **`@grafana/plugin-e2e`** for end-to-end testing. Read @./.config/AGENTS/e2e-testing.md before writing or modifying e2e tests.
|
|
@@ -99,6 +99,61 @@ Edit the `tsconfig.json` file in the project root in order to extend the TypeScr
|
|
|
99
99
|
|
|
100
100
|
---
|
|
101
101
|
|
|
102
|
+
{{#if useRspack}}
|
|
103
|
+
### Extending the Rspack config
|
|
104
|
+
|
|
105
|
+
Follow these steps to extend the basic Rspack configuration that lives under `.config/`:
|
|
106
|
+
|
|
107
|
+
#### 1. Create a new Rspack configuration file
|
|
108
|
+
|
|
109
|
+
Create a new config file that is going to extend the basic one provided by Grafana.
|
|
110
|
+
It can live in the project root, e.g. `rspack.config.ts`.
|
|
111
|
+
|
|
112
|
+
#### 2. Merge the basic config provided by Grafana and your custom setup
|
|
113
|
+
|
|
114
|
+
We are going to use [`rspack-merge`](https://github.com/rstackjs/rspack-merge) for this.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// rspack.config.ts
|
|
118
|
+
import type { Configuration } from '@rspack/core';
|
|
119
|
+
import { merge } from 'rspack-merge';
|
|
120
|
+
import grafanaConfig, { type Env } from './.config/rspack/rspack.config.ts';
|
|
121
|
+
|
|
122
|
+
const config = async (env: Env): Promise<Configuration> => {
|
|
123
|
+
const baseConfig = await grafanaConfig(env);
|
|
124
|
+
|
|
125
|
+
return merge(baseConfig, {
|
|
126
|
+
// Add custom config here...
|
|
127
|
+
output: {
|
|
128
|
+
asyncChunks: true,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export default config;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The Rspack CLI loads this file as native ESM, so use `import.meta.dirname` instead of `__dirname` and give relative imports a `.ts` extension.
|
|
137
|
+
|
|
138
|
+
#### 3. Update the `package.json` to use the new Rspack config
|
|
139
|
+
|
|
140
|
+
We need to update the `scripts` in the `package.json` to use the extended Rspack configuration.
|
|
141
|
+
|
|
142
|
+
**Update for `build`:**
|
|
143
|
+
|
|
144
|
+
```diff
|
|
145
|
+
-"build": "rspack -c ./.config/rspack/rspack.config.ts --env production",
|
|
146
|
+
+"build": "rspack -c ./rspack.config.ts --env production",
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Update for `dev`:**
|
|
150
|
+
|
|
151
|
+
```diff
|
|
152
|
+
-"dev": "rspack -w -c ./.config/rspack/rspack.config.ts --env development",
|
|
153
|
+
+"dev": "rspack -w -c ./rspack.config.ts --env development",
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
{{else}}
|
|
102
157
|
### Extending the Webpack config
|
|
103
158
|
|
|
104
159
|
Follow these steps to extend the basic Webpack configuration that lives under `.config/`:
|
|
@@ -150,6 +205,7 @@ We need to update the `scripts` in the `package.json` to use the extended Webpac
|
|
|
150
205
|
+"dev": "webpack -w -c ./webpack.config.ts --env development",
|
|
151
206
|
```
|
|
152
207
|
|
|
208
|
+
{{/if}}
|
|
153
209
|
### Configure grafana image to use when running docker
|
|
154
210
|
|
|
155
211
|
By default, `grafana-enterprise` will be used as the docker image for all docker related commands. If you want to override this behavior, simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
{{#unless
|
|
1
|
+
{{#unless useRspack}}import type { Configuration, ExternalItemFunctionData } from 'webpack';{{/unless}}{{#if useRspack}}
|
|
2
2
|
import type { RspackOptions, ExternalItemFunctionData } from '@rspack/core';{{/if}}
|
|
3
3
|
|
|
4
|
-
{{#unless
|
|
4
|
+
{{#unless useRspack}} type ExternalsType = Configuration['externals'];{{/unless}}{{#if useRspack}}type ExternalsType = RspackOptions['externals'];{{/if}}
|
|
5
5
|
|
|
6
6
|
export const externals: ExternalsType = [
|
|
7
7
|
// Required for dynamic publicPath resolution
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Compiler } from '@rspack/core';
|
|
2
|
+
import DiagnosticsWebpackPlugin from 'diagnostics-webpack-plugin';
|
|
3
|
+
|
|
4
|
+
type DiagnosticsOptions = ConstructorParameters<typeof DiagnosticsWebpackPlugin>[0];
|
|
5
|
+
|
|
6
|
+
// diagnostics-webpack-plugin validates its options through compiler.hooks.validate, which webpack added
|
|
7
|
+
// in 5.106 and rspack doesn't have yet. a no-op hook lets the plugin run, without its options check.
|
|
8
|
+
// once rspack adds the hook, delete this wrapper and use diagnostics-webpack-plugin directly
|
|
9
|
+
class DiagnosticsRspackPlugin {
|
|
10
|
+
plugin: DiagnosticsWebpackPlugin;
|
|
11
|
+
|
|
12
|
+
constructor(options: DiagnosticsOptions) {
|
|
13
|
+
this.plugin = new DiagnosticsWebpackPlugin(options);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
apply(compiler: Compiler) {
|
|
17
|
+
const validate = { tap: () => {} };
|
|
18
|
+
const hooks = new Proxy(compiler.hooks, {
|
|
19
|
+
get: (target, prop) => (prop === 'validate' ? validate : Reflect.get(target, prop, target)),
|
|
20
|
+
});
|
|
21
|
+
const compilerWithValidate = new Proxy(compiler, {
|
|
22
|
+
get: (target, prop) => (prop === 'hooks' ? hooks : Reflect.get(target, prop, target)),
|
|
23
|
+
});
|
|
24
|
+
// @ts-expect-error -- the plugin is typed against webpack's Compiler
|
|
25
|
+
this.plugin.apply(compilerWithValidate);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default DiagnosticsRspackPlugin;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Compilation, type Compiler } from '@rspack/core';
|
|
2
|
+
|
|
3
|
+
const PLUGIN_NAME = 'LicenseRspackPlugin';
|
|
4
|
+
const CHUNK_LICENSE_PATTERN = /\.LICENSE\.txt$/;
|
|
5
|
+
|
|
6
|
+
// This Rspack plugin works alongside SwcJsMinimizerRspackPlugin by taking all license file comments,
|
|
7
|
+
// deduping them and then writing them to a single file.
|
|
8
|
+
export class LicenseRspackPlugin {
|
|
9
|
+
apply(compiler: Compiler) {
|
|
10
|
+
compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
|
|
11
|
+
compilation.hooks.processAssets.tap(
|
|
12
|
+
{
|
|
13
|
+
name: PLUGIN_NAME,
|
|
14
|
+
// after the minimizer (PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE) has extracted the comments
|
|
15
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE + 1,
|
|
16
|
+
},
|
|
17
|
+
(assets) => {
|
|
18
|
+
const chunkLicenseFiles = Object.keys(assets)
|
|
19
|
+
.filter((assetName) => CHUNK_LICENSE_PATTERN.test(assetName))
|
|
20
|
+
.sort();
|
|
21
|
+
|
|
22
|
+
if (chunkLicenseFiles.length === 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const comments = new Set<string>();
|
|
27
|
+
for (const assetName of chunkLicenseFiles) {
|
|
28
|
+
const content = assets[assetName].source().toString();
|
|
29
|
+
content
|
|
30
|
+
.split(/\n{2,}/)
|
|
31
|
+
.map((comment) => comment.trim())
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.forEach((comment) => comments.add(comment));
|
|
34
|
+
compilation.deleteAsset(assetName);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { RawSource } = compiler.rspack.sources;
|
|
38
|
+
compilation.emitAsset('LICENSE.txt', new RawSource([...comments].join('\n\n') + '\n'));
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { type Compiler } from '@rspack/core';
|
|
3
|
+
import { WebSocketServer } from 'ws';
|
|
4
|
+
|
|
5
|
+
interface RspackLiveReloadPluginOptions {
|
|
6
|
+
port?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Serves /livereload.js and tells connected browsers to reload after every rebuild. The scaffolded
|
|
10
|
+
// Grafana docker image adds <script src="http://localhost:35729/livereload.js"> to its index.html.
|
|
11
|
+
class RspackLiveReloadPlugin {
|
|
12
|
+
port: number;
|
|
13
|
+
httpServer: ReturnType<typeof createServer> | null = null;
|
|
14
|
+
server: WebSocketServer | null = null;
|
|
15
|
+
// each rebuild retries the port, so live reload starts by itself once the port is free again
|
|
16
|
+
hasWarnedDisabled = false;
|
|
17
|
+
|
|
18
|
+
constructor(options: RspackLiveReloadPluginOptions = {}) {
|
|
19
|
+
this.port = options.port ?? 35729;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
apply(compiler: Compiler) {
|
|
23
|
+
compiler.hooks.afterEmit.tap('RspackLiveReloadPlugin', () => {
|
|
24
|
+
this._startServer();
|
|
25
|
+
this._notifyClients();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_startServer() {
|
|
30
|
+
if (this.server) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.httpServer = createServer((req, res) => {
|
|
35
|
+
if (req.url === '/livereload.js') {
|
|
36
|
+
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
37
|
+
res.end(this._getLiveReloadScript());
|
|
38
|
+
} else {
|
|
39
|
+
res.writeHead(404);
|
|
40
|
+
res.end('Not Found');
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
this.server = new WebSocketServer({ server: this.httpServer });
|
|
45
|
+
// live reload is a convenience, so a port that is already taken must not take the watch build down.
|
|
46
|
+
// ws re-emits the http server's errors on the WebSocketServer, so both need a listener
|
|
47
|
+
const disableLiveReload = (error: NodeJS.ErrnoException) => {
|
|
48
|
+
if (!this.httpServer) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!this.hasWarnedDisabled) {
|
|
52
|
+
this.hasWarnedDisabled = true;
|
|
53
|
+
const reason = error.code === 'EADDRINUSE' ? `port ${this.port} is already in use` : error.message;
|
|
54
|
+
console.warn(`LiveReload disabled: ${reason}. The build keeps watching without reloading the browser.`);
|
|
55
|
+
}
|
|
56
|
+
this.server?.close();
|
|
57
|
+
this.server = null;
|
|
58
|
+
this.httpServer = null;
|
|
59
|
+
};
|
|
60
|
+
this.httpServer.on('error', disableLiveReload);
|
|
61
|
+
this.server.on('error', disableLiveReload);
|
|
62
|
+
this.httpServer.listen(this.port, () => {
|
|
63
|
+
console.log(`LiveReload server started on http://localhost:${this.port}`);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_notifyClients() {
|
|
68
|
+
if (!this.server) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.server.clients.forEach((client) => {
|
|
73
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
74
|
+
client.send(JSON.stringify({ action: 'reload' }));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_getLiveReloadScript() {
|
|
80
|
+
return `
|
|
81
|
+
(function() {
|
|
82
|
+
if (typeof WebSocket === 'undefined') return;
|
|
83
|
+
const ws = new WebSocket('ws://localhost:${this.port}');
|
|
84
|
+
ws.onmessage = function(event) {
|
|
85
|
+
const data = JSON.parse(event.data);
|
|
86
|
+
if (data.action === 'reload') {
|
|
87
|
+
window.location.reload();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
})();
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default RspackLiveReloadPlugin;
|
|
@@ -5,24 +5,32 @@
|
|
|
5
5
|
* https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations#extend-the-webpack-config
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
BannerPlugin,
|
|
10
|
+
Compilation,
|
|
11
|
+
CopyRspackPlugin,
|
|
12
|
+
SubresourceIntegrityPlugin,
|
|
13
|
+
SwcJsMinimizerRspackPlugin,
|
|
14
|
+
type Configuration,
|
|
15
|
+
} from '@rspack/core';
|
|
10
16
|
import { TsCheckerRspackPlugin } from 'ts-checker-rspack-plugin';
|
|
11
17
|
import path from 'path';
|
|
12
18
|
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
|
|
13
|
-
import TerserPlugin from 'terser-webpack-plugin';
|
|
14
19
|
import { RspackVirtualModulePlugin } from 'rspack-plugin-virtual-module';
|
|
15
20
|
|
|
16
|
-
import RspackLiveReloadPlugin from './
|
|
21
|
+
import RspackLiveReloadPlugin from './LiveReloadRspackPlugin.ts';
|
|
17
22
|
import { BuildModeRspackPlugin } from './BuildModeRspackPlugin.ts';
|
|
23
|
+
import { LicenseRspackPlugin } from './LicenseRspackPlugin.ts';
|
|
24
|
+
import DiagnosticsRspackPlugin from './DiagnosticsRspackPlugin.ts';
|
|
18
25
|
import { DIST_DIR, SOURCE_DIR } from '../bundler/constants.ts';
|
|
19
26
|
import { getCPConfigVersion, getEntries, getPackageJson, getPluginJson, isWSL } from '../bundler/utils.ts';
|
|
20
27
|
import { externals } from '../bundler/externals.ts';
|
|
21
28
|
import { copyFilePatterns } from '../bundler/copyFiles.ts';
|
|
22
29
|
|
|
23
|
-
const { SubresourceIntegrityPlugin } = rspack.experiments;
|
|
24
30
|
const pluginJson = getPluginJson();
|
|
31
|
+
const pluginId = pluginJson.id;
|
|
25
32
|
const cpVersion = getCPConfigVersion();
|
|
33
|
+
const pluginVersion = getPackageJson().version;
|
|
26
34
|
const virtualPublicPath = new RspackVirtualModulePlugin({
|
|
27
35
|
'grafana-public-path': `
|
|
28
36
|
import amdMetaModule from 'amd-module';
|
|
@@ -30,11 +38,15 @@ import amdMetaModule from 'amd-module';
|
|
|
30
38
|
__webpack_public_path__ =
|
|
31
39
|
amdMetaModule && amdMetaModule.uri
|
|
32
40
|
? amdMetaModule.uri.slice(0, amdMetaModule.uri.lastIndexOf('/') + 1)
|
|
33
|
-
: 'public/plugins/${
|
|
41
|
+
: 'public/plugins/${pluginId}/';
|
|
34
42
|
`,
|
|
35
43
|
});
|
|
36
44
|
|
|
37
|
-
|
|
45
|
+
export type Env = {
|
|
46
|
+
[key: string]: true | string | Env;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const config = async (env: Env): Promise<Configuration> => {
|
|
38
50
|
const baseConfig: Configuration = {
|
|
39
51
|
context: path.join(process.cwd(), SOURCE_DIR),
|
|
40
52
|
|
|
@@ -117,19 +129,11 @@ const config = async (env): Promise<Configuration> => {
|
|
|
117
129
|
optimization: {
|
|
118
130
|
minimize: Boolean(env.production),
|
|
119
131
|
minimizer: [
|
|
120
|
-
new
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
},
|
|
126
|
-
terserOptions: {
|
|
127
|
-
format: {
|
|
128
|
-
comments: (_, { type, value }) => type === 'comment2' && value.trim().startsWith('[create-plugin]'),
|
|
129
|
-
},
|
|
130
|
-
compress: {
|
|
131
|
-
drop_console: ['log', 'info'],
|
|
132
|
-
},
|
|
132
|
+
new SwcJsMinimizerRspackPlugin({
|
|
133
|
+
extractComments: { banner: false },
|
|
134
|
+
minimizerOptions: {
|
|
135
|
+
format: { comments: false },
|
|
136
|
+
compress: { pure_funcs: ['console.log', 'console.info'] },
|
|
133
137
|
},
|
|
134
138
|
}),
|
|
135
139
|
],
|
|
@@ -145,32 +149,37 @@ const config = async (env): Promise<Configuration> => {
|
|
|
145
149
|
type: 'amd',
|
|
146
150
|
},
|
|
147
151
|
path: path.resolve(process.cwd(), DIST_DIR),
|
|
148
|
-
publicPath: `public/plugins/${
|
|
149
|
-
uniqueName:
|
|
152
|
+
publicPath: `public/plugins/${pluginId}/`,
|
|
153
|
+
uniqueName: pluginId,
|
|
150
154
|
crossOriginLoading: 'anonymous',
|
|
151
155
|
},
|
|
152
156
|
|
|
153
157
|
plugins: [
|
|
154
158
|
new BuildModeRspackPlugin(),
|
|
159
|
+
new LicenseRspackPlugin(),
|
|
155
160
|
virtualPublicPath,
|
|
156
161
|
// Insert create plugin version information into the bundle
|
|
157
|
-
new
|
|
158
|
-
banner:
|
|
162
|
+
new BannerPlugin({
|
|
163
|
+
banner: [
|
|
164
|
+
`/* [create-plugin] version: ${cpVersion} */`,
|
|
165
|
+
`/* [create-plugin] plugin: ${pluginId}@${pluginVersion} */`,
|
|
166
|
+
].join('\n'),
|
|
159
167
|
raw: true,
|
|
160
168
|
entryOnly: true,
|
|
169
|
+
// after minification to prevent banner removal and before source maps and hashes are generated so they include it.
|
|
170
|
+
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE + 1,
|
|
161
171
|
}),
|
|
162
|
-
new
|
|
172
|
+
new CopyRspackPlugin({
|
|
163
173
|
patterns: copyFilePatterns,
|
|
164
174
|
}),
|
|
165
|
-
// Replace certain template-variables in the README and plugin.json
|
|
166
175
|
new ReplaceInFileWebpackPlugin([
|
|
167
176
|
{
|
|
168
177
|
dir: DIST_DIR,
|
|
169
|
-
|
|
178
|
+
test: [/(^|\/)plugin\.json$/, /(^|\/)README\.md$/],
|
|
170
179
|
rules: [
|
|
171
180
|
{
|
|
172
181
|
search: /\%VERSION\%/g,
|
|
173
|
-
replace:
|
|
182
|
+
replace: pluginVersion,
|
|
174
183
|
},
|
|
175
184
|
{
|
|
176
185
|
search: /\%TODAY\%/g,
|
|
@@ -178,7 +187,7 @@ const config = async (env): Promise<Configuration> => {
|
|
|
178
187
|
},
|
|
179
188
|
{
|
|
180
189
|
search: /\%PLUGIN_ID\%/g,
|
|
181
|
-
replace:
|
|
190
|
+
replace: pluginId,
|
|
182
191
|
},
|
|
183
192
|
],
|
|
184
193
|
},
|
|
@@ -196,9 +205,9 @@ const config = async (env): Promise<Configuration> => {
|
|
|
196
205
|
},
|
|
197
206
|
typescript: { configFile: path.join(process.cwd(), 'tsconfig.json') },
|
|
198
207
|
}),
|
|
199
|
-
new
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
new DiagnosticsRspackPlugin({
|
|
209
|
+
lintOnStart: false, // don't lint on start, only lint changed files
|
|
210
|
+
checks: [{ use: 'eslint', extensions: ['ts', 'tsx'] }],
|
|
202
211
|
}),
|
|
203
212
|
]
|
|
204
213
|
: []),
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"@grafana/plugin-e2e": "^3.15.2",
|
|
21
21
|
"@grafana/sign-plugin": "^3.3.3",
|
|
22
22
|
"@grafana/tsconfig": "^2.2.0",
|
|
23
|
-
"@playwright/test": "^1.62.1",{{#if
|
|
24
|
-
"@rspack/core": "^
|
|
25
|
-
"@rspack/cli": "^
|
|
23
|
+
"@playwright/test": "^1.62.1",{{#if useRspack}}
|
|
24
|
+
"@rspack/core": "^2.2.0",
|
|
25
|
+
"@rspack/cli": "^2.2.0",{{/if}}
|
|
26
26
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
27
27
|
"@swc/core": "^1.15.0",
|
|
28
28
|
"@swc/helpers": "^0.5.0",
|
|
@@ -32,19 +32,18 @@
|
|
|
32
32
|
"@types/jest": "^30.0.0",
|
|
33
33
|
"@types/node": "^24.0.0",
|
|
34
34
|
"@types/react": "^19.0.0",
|
|
35
|
-
"@types/react-dom": "^19.0.0",{{#if
|
|
35
|
+
"@types/react-dom": "^19.0.0",{{#if useRspack}}
|
|
36
36
|
"@types/ws": "^8.18.1",{{/if}}
|
|
37
37
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
38
|
-
"@typescript-eslint/parser": "^8.38.0",{{#unless
|
|
38
|
+
"@typescript-eslint/parser": "^8.38.0",{{#unless useRspack}}
|
|
39
39
|
"copy-webpack-plugin": "^14.0.0",{{/unless}}
|
|
40
|
-
"css-loader": "^7.1.0",
|
|
41
|
-
"diagnostics-webpack-plugin": "^1.0.1",
|
|
40
|
+
"css-loader": "^7.1.0",
|
|
41
|
+
"diagnostics-webpack-plugin": "^1.0.1",
|
|
42
42
|
"eslint": "^9.32.0",
|
|
43
43
|
"eslint-config-prettier": "^10.1.0",
|
|
44
44
|
"eslint-plugin-jsdoc": "^52.0.0",
|
|
45
45
|
"eslint-plugin-react": "^7.37.0",
|
|
46
|
-
"eslint-plugin-react-hooks": "^7.1.0",{{#
|
|
47
|
-
"eslint-webpack-plugin": "^5.0.0",{{/if}}{{#unless useExperimentalRspack}}
|
|
46
|
+
"eslint-plugin-react-hooks": "^7.1.0",{{#unless useRspack}}
|
|
48
47
|
"fork-ts-checker-webpack-plugin": "^9.1.0",{{/unless}}
|
|
49
48
|
"identity-obj-proxy": "^3.0.0",
|
|
50
49
|
"imports-loader": "^5.0.0",
|
|
@@ -53,26 +52,27 @@
|
|
|
53
52
|
"jest-canvas-mock": "^2.5.2",
|
|
54
53
|
"jest-environment-jsdom": "^30.5.0",
|
|
55
54
|
"prettier": "^3.6.0",
|
|
56
|
-
"replace-in-file-webpack-plugin": "^1.0.0",{{#if
|
|
55
|
+
"replace-in-file-webpack-plugin": "^1.0.0",{{#if useRspack}}
|
|
56
|
+
"rspack-merge": "^1.0.1",
|
|
57
57
|
"rspack-plugin-virtual-module": "^1.0.0",{{/if}}
|
|
58
58
|
"sass": "^1.89.0",
|
|
59
59
|
"sass-loader": "^16.0.0",
|
|
60
60
|
"semver": "^7.7.0",
|
|
61
|
-
"style-loader": "^4.0.0",{{#unless
|
|
62
|
-
"swc-loader": "^0.2.0",
|
|
63
|
-
"terser-webpack-plugin": "^5.3.0",
|
|
64
|
-
"ts-node": "^10.9.0",{{#if
|
|
65
|
-
"ts-checker-rspack-plugin": "^1.
|
|
61
|
+
"style-loader": "^4.0.0",{{#unless useRspack}}
|
|
62
|
+
"swc-loader": "^0.2.0",
|
|
63
|
+
"terser-webpack-plugin": "^5.3.0",{{/unless}}
|
|
64
|
+
"ts-node": "^10.9.0",{{#if useRspack}}
|
|
65
|
+
"ts-checker-rspack-plugin": "^1.7.0",{{/if}}
|
|
66
66
|
"typescript": "5.9.2",
|
|
67
|
-
"webpack": "^5.106.0"{{#unless
|
|
67
|
+
"webpack": "^5.106.0"{{#unless useRspack}},
|
|
68
68
|
"webpack-cli": "^6.0.0",
|
|
69
69
|
"webpack-livereload-plugin": "^3.0.2",
|
|
70
70
|
"webpack-subresource-integrity": "^5.1.0",
|
|
71
|
-
"webpack-virtual-modules": "^0.6.2"{{/unless}}{{#if
|
|
71
|
+
"webpack-virtual-modules": "^0.6.2"{{/unless}}{{#if useRspack}},
|
|
72
72
|
"ws": "^8.13.0"{{/if}}
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
|
-
"node": ">=22"
|
|
75
|
+
"node": ">=22.23"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@emotion/css": "11.10.6",
|