Skip to content

Commit

Permalink
Add github action, update packages and config.
Browse files Browse the repository at this point in the history
  • Loading branch information
fmassot committed May 13, 2023
1 parent 6a7bc31 commit 352ca13
Show file tree
Hide file tree
Showing 24 changed files with 2,281 additions and 2,134 deletions.
3 changes: 2 additions & 1 deletion .config/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-eslint-config
*/
{
"extends": ["@grafana/eslint-config"],
Expand Down
2 changes: 1 addition & 1 deletion .config/.prettierrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ module.exports = {
"singleQuote": true,
"useTabs": false,
"tabWidth": 2
};
};
3 changes: 2 additions & 1 deletion .config/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ARG grafana_version=latest
ARG grafana_image=grafana-enterprise

FROM grafana/grafana:9.5.1
FROM grafana/${grafana_image}:${grafana_version}

# Make it as simple as possible to access the grafana instance for development purposes
# Do NOT enable these settings in a public facing / production grafana instance
Expand Down
52 changes: 48 additions & 4 deletions .config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ to issues around working with the project.
Edit the `.eslintrc` file in the project root in order to extend the ESLint configuration.

**Example:**

```json
{
"extends": "./.config/.eslintrc",
"rules": {
"react/prop-types": "off"
"react/prop-types": "off"
}
}
```
Expand All @@ -32,10 +33,11 @@ Edit the `.eslintrc` file in the project root in order to extend the ESLint conf
Edit the `.prettierrc.js` file in the project root in order to extend the Prettier configuration.

**Example:**

```javascript
module.exports = {
// Prettier configuration provided by Grafana scaffolding
...require("./.config/.prettierrc.js"),
...require('./.config/.prettierrc.js'),

semi: false,
};
Expand All @@ -50,7 +52,23 @@ There are two configuration in the project root that belong to Jest: `jest-setup
**`jest-setup.js`:** A file that is run before each test file in the suite is executed. We are using it to
set up the Jest DOM for the testing library and to apply some polyfills. ([link to Jest docs](https://jestjs.io/docs/configuration#setupfilesafterenv-array))

**`jest.config.js`:** The main Jest configuration file that is extending our basic Grafana-tailored setup. ([link to Jest docs](https://jestjs.io/docs/configuration))
**`jest.config.js`:** The main Jest configuration file that extends the Grafana recommended setup. ([link to Jest docs](https://jestjs.io/docs/configuration))

#### ESM errors with Jest

A common issue found with the current jest config involves importing an npm package which only offers an ESM build. These packages cause jest to error with `SyntaxError: Cannot use import statement outside a module`. To work around this we provide a list of known packages to pass to the `[transformIgnorePatterns](https://jestjs.io/docs/configuration#transformignorepatterns-arraystring)` jest configuration property. If need be this can be extended in the following way:

```javascript
process.env.TZ = 'UTC';
const { grafanaESModules, nodeModulesToTransform } = require('./config/jest/utils');

module.exports = {
// Jest configuration provided by Grafana
...require('./.config/jest.config'),
// Inform jest to only transform specific node_module packages.
transformIgnorePatterns: [nodeModulesToTransform([...grafanaESModules, 'packageName'])],
};
```

---

Expand All @@ -59,6 +77,7 @@ set up the Jest DOM for the testing library and to apply some polyfills. ([link
Edit the `tsconfig.json` file in the project root in order to extend the TypeScript configuration.

**Example:**

```json
{
"extends": "./.config/tsconfig.json",
Expand All @@ -80,6 +99,7 @@ Create a new config file that is going to extend the basic one provided by Grafa
It can live in the project root, e.g. `webpack.config.ts`.

#### 2. Merge the basic config provided by Grafana and your custom setup

We are going to use [`webpack-merge`](https://github.com/survivejs/webpack-merge) for this.

```typescript
Expand All @@ -100,21 +120,45 @@ const config = async (env): Promise<Configuration> => {
};

export default config;

```

#### 3. Update the `package.json` to use the new Webpack config

We need to update the `scripts` in the `package.json` to use the extended Webpack configuration.

**Update for `build`:**

```diff
-"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",
+"build": "webpack -c ./webpack.config.ts --env production",
```

**Update for `dev`:**

```diff
-"dev": "webpack -w -c ./.config/webpack/webpack.config.ts --env development",
+"dev": "webpack -w -c ./webpack.config.ts --env development",
```

### Configure grafana image to use when running docker

By default `grafana-enterprise` will be used as the docker image for all docker related commands. If you want to override this behaviour simply alter the `docker-compose.yaml` by adding the following build arg `grafana_image`.

**Example:**

```yaml
version: '3.7'

services:
grafana:
container_name: 'myorg-basic-app'
build:
context: ./.config
args:
grafana_version: ${GRAFANA_VERSION:-9.1.2}
grafana_image: ${GRAFANA_IMAGE:-grafana}
```
In this example we are assigning the environment variable `GRAFANA_IMAGE` to the build arg `grafana_image` with a default value of `grafana`. This will give you the possibility to set the value while running the docker-compose commands which might be convinent in some scenarios.

---
3 changes: 2 additions & 1 deletion .config/jest-setup.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-jest-config
*/

import '@testing-library/jest-dom';
Expand Down
13 changes: 10 additions & 3 deletions .config/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-jest-config
*/

const path = require('path');
const { grafanaESModules, nodeModulesToTransform } = require('./jest/utils');

module.exports = {
moduleNameMapper: {
"\\.(css|scss|sass)$": "identity-obj-proxy",
'\\.(css|scss|sass)$': 'identity-obj-proxy',
'react-inlinesvg': path.resolve(__dirname, 'jest', 'mocks', 'react-inlinesvg.tsx'),
},
modulePaths: ['<rootDir>/src'],
setupFilesAfterEnv: ['<rootDir>/jest-setup.js'],
Expand All @@ -32,5 +37,7 @@ module.exports = {
},
],
},
transformIgnorePatterns: [],
// Jest will throw `Cannot use import statement outside module` if it tries to load an
// ES module without it being transformed first. ./config/README.md#esm-errors-with-jest
transformIgnorePatterns: [nodeModulesToTransform(grafanaESModules)],
};
25 changes: 25 additions & 0 deletions .config/jest/mocks/react-inlinesvg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Due to the grafana/ui Icon component making fetch requests to
// `/public/img/icon/<icon_name>.svg` we need to mock react-inlinesvg to prevent
// the failed fetch requests from displaying errors in console.

import React from 'react';

type Callback = (...args: any[]) => void;

export interface StorageItem {
content: string;
queue: Callback[];
status: string;
}

export const cacheStore: { [key: string]: StorageItem } = Object.create(null);

const SVG_FILE_NAME_REGEX = /(.+)\/(.+)\.svg$/;

const InlineSVG = ({ src }: { src: string }) => {
// testId will be the file name without extension (e.g. `public/img/icons/angle-double-down.svg` -> `angle-double-down`)
const testId = src.replace(SVG_FILE_NAME_REGEX, '$2');
return <svg xmlns="http://www.w3.org/2000/svg" data-testid={testId} viewBox="0 0 24 24" />;
};

export default InlineSVG;
29 changes: 29 additions & 0 deletions .config/jest/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
*/

/*
* This utility function is useful in combination with jest `transformIgnorePatterns` config
* to transform specific packages (e.g.ES modules) in a projects node_modules folder.
*/
const nodeModulesToTransform = (moduleNames) => `node_modules\/(?!(${moduleNames.join('|')})\/)`;

// Array of known nested grafana package dependencies that only bundle an ESM version
const grafanaESModules = [
'.pnpm', // Support using pnpm symlinked packages
'd3',
'd3-color',
'd3-force',
'd3-interpolate',
'd3-scale-chromatic',
'ol',
'react-colorful',
'uuid',
];

module.exports = {
nodeModulesToTransform,
grafanaESModules
}
3 changes: 2 additions & 1 deletion .config/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-typescript-config
*/
{
"compilerOptions": {
Expand Down
38 changes: 18 additions & 20 deletions .config/webpack/utils.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
import fs from 'fs';
import path from 'path';
import util from 'util';
import glob from 'glob';
import { glob } from 'glob';
import { SOURCE_DIR } from './constants';

const globAsync = util.promisify(glob);

export function getPackageJson() {
return require(path.resolve(process.cwd(), 'package.json'));
}

export function getPluginId() {
const { id } = require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));

return id;
export function getPluginJson() {
return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`));
}

export function hasReadme() {
return fs.existsSync(path.resolve(process.cwd(), SOURCE_DIR, 'README.md'));
}

// Support bundling nested plugins by finding all plugin.json files in src directory
// then checking for a sibling module.[jt]sx? file.
export async function getEntries(): Promise<Record<string, string>> {
const parent = '..';
const pluginsJson = await globAsync('**/src/**/plugin.json');

const plugins = await Promise.all(pluginsJson.map(pluginJson => {
const folder = path.dirname(pluginJson);
return globAsync(`${folder}/module.{ts,tsx,js}`);
}));
const pluginsJson = await glob('**/src/**/plugin.json', { absolute: true });

const plugins = await Promise.all(pluginsJson.map((pluginJson) => {
const folder = path.dirname(pluginJson);
return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true });
})
);

return plugins.reduce((result, modules) => {
return modules.reduce((result, module) => {
const pluginPath = path.resolve(path.dirname(module), parent);
const pluginName = path.basename(pluginPath);
const entryName = plugins.length > 1 ? `${pluginName}/module` : 'module';
result[entryName] = path.join(parent, module);
const pluginPath = path.dirname(module);
const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, '');
const entryName = pluginName === '' ? 'module' : `${pluginName}/module`;

result[entryName] = module;
return result;
}, result);
}, {});
}
}
16 changes: 9 additions & 7 deletions .config/webpack/webpack.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* ⚠️⚠️⚠️ THIS FILE WAS SCAFFOLDED BY `@grafana/create-plugin`. DO NOT EDIT THIS FILE DIRECTLY. ⚠️⚠️⚠️
*
* In order to extend the configuration follow the steps in .config/README.md
* In order to extend the configuration follow the steps in
* https://grafana.github.io/plugin-tools/docs/advanced-configuration#extending-the-webpack-config
*/

import CopyWebpackPlugin from 'copy-webpack-plugin';
Expand All @@ -12,9 +13,11 @@ import path from 'path';
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
import { Configuration } from 'webpack';

import { getPackageJson, getPluginId, hasReadme, getEntries } from './utils';
import { getPackageJson, getPluginJson, hasReadme, getEntries } from './utils';
import { SOURCE_DIR, DIST_DIR } from './constants';

const pluginJson = getPluginJson();

const config = async (env): Promise<Configuration> => ({
cache: {
type: 'filesystem',
Expand Down Expand Up @@ -96,7 +99,6 @@ const config = async (env): Promise<Configuration> => ({
use: ["style-loader", "css-loader"]
},
{
exclude: /(node_modules)/,
test: /\.s[ac]ss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
Expand All @@ -105,7 +107,7 @@ const config = async (env): Promise<Configuration> => ({
type: 'asset/resource',
generator: {
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${getPluginId()}/img/`,
publicPath: `public/plugins/${pluginJson.id}/img/`,
outputPath: 'img/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
},
Expand All @@ -115,7 +117,7 @@ const config = async (env): Promise<Configuration> => ({
type: 'asset/resource',
generator: {
// Keep publicPath relative for host.com/grafana/ deployments
publicPath: `public/plugins/${getPluginId()}/fonts`,
publicPath: `public/plugins/${pluginJson.id}/fonts`,
outputPath: 'fonts/',
filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]',
},
Expand All @@ -125,7 +127,7 @@ const config = async (env): Promise<Configuration> => ({

output: {
clean: {
keep: /gpx_.*/,
keep: new RegExp(`.*?_(amd64|arm(64)?)(.exe)?`),
},
filename: '[name].js',
library: {
Expand Down Expand Up @@ -169,7 +171,7 @@ const config = async (env): Promise<Configuration> => ({
},
{
search: /\%PLUGIN_ID\%/g,
replace: getPluginId(),
replace: pluginJson.id,
},
],
},
Expand Down
Loading

0 comments on commit 352ca13

Please sign in to comment.