grafana/toolkit: Improve readme (#18747)

* Improve grafana toolkit related readmes

* Post review updates

* Update packages/grafana-toolkit/README.md

* Update packages/grafana-toolkit/README.md
pull/18985/head
Dominik Prokop 6 years ago committed by GitHub
parent 05434cffb1
commit e2b1cdd7ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 205
      packages/grafana-toolkit/README.md
  2. 40
      style_guides/themes.md

@ -1,77 +1,98 @@
# Grafana Toolkit
Make sure to run `yarn install` before trying anything! Otherwise you may see unknown command grafana-toolkit and spend a while tracking that down.
# grafana-toolkit
grafana-toolkit is CLI that enables efficient development of Grafana extensions
## Rationale
Historically, creating Grafana extension was an exercise of reverse engineering and ceremony around testing, developing and eventually building the plugin. We want to help our community to focus on the core value of their plugins rather than all the setup required to develop an extension.
## Installation
## Internal development
Typically plugins should be developed using the `@grafana/toolkit` import from npm. However, when working on the toolkit, you may want to use the local version while underdevelopment. This works, but is a little flakey.
You can either add grafana-toolkit to your extension's `package.json` file by running
`yarn add @grafana/toolkit` `npm instal @grafana/toolkit` or use one of our extension templates:
- [React Panel](https://github.com/grafana/simple-react-panel)
- [Angular Panel](https://github.com/grafana/simple-angular-panel)
1. navigate to `packages/grafana-toolkit` and run `yarn link`.
2. in your plugin, run `npx grafana-toolkit plugin:dev --yarnlink`
### Updating your extension to use grafana-toolkit
In order to start using grafana-toolkit in your extension you need to follow the steps below:
1. Add `@grafana/toolkit` package to your project
2. Create `tsconfig.json` file in the root dir of your extension and paste the code below:
```json
{
"extends": "./node_modules/@grafana/toolkit/src/config/tsconfig.plugin.json",
"include": ["src", "types"],
"compilerOptions": {
"rootDir": "./src",
"baseUrl": "./src",
"typeRoots": ["./node_modules/@types"]
}
}
```
Step 2 will add all the same dependencies to your development plugin as the toolkit. These are typically used from the node_modules folder
3. Create `.prettierrc.js` file in the root dir of your extension and paste the code below:
```js
module.exports = {
...require("./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json"),
};
```
4. In your `package.json` file add following scripts:
```json
"scripts": {
"build": "grafana-toolkit plugin:build",
"test": "grafana-toolkit plugin:test",
"dev": "grafana-toolkit plugin:dev",
"watch": "grafana-toolkit plugin:dev --watch"
},
```
TODO: Experiment with [yalc](https://github.com/whitecolor/yalc) for linking packages
## Usage
With grafana-toolkit we put in your hands a CLI that addresses common tasks performed when working on Grafana extension:
- `grafana-toolkit plugin:test`
- `grafana-toolkit plugin:dev`
- `grafana-toolkit plugin:build`
### Developing extensions
`grafana-toolkit plugin:dev`
### Publishing to npm
The publish process is now manual. Follow the steps to publish @grafana/toolkit to npm
1. From Grafana root dir: `./node_modules/.bin/grafana-toolkit toolkit:build`
2. `cd packages/grafana-toolkit/dist`
3. Open `package.json`, change version according to current version on npm (https://www.npmjs.com/package/@grafana/toolkit)
4. Run `npm publish --tag next` - for dev purposes we now publish on `next` channel
Creates development build that's easy to play with and debug using common browser tooling
Note, that for publishing you need to be part of Grafana npm org and you need to be logged in to npm in your terminal (`npm login`).
Available options:
- `-w`, `--watch` - run development task in a watch mode
### Testing extensions
`grafana-toolkit plugin:test`
## Grafana extensions development with grafana-toolkit overview
### Available tasks
#### `grafana-toolkit plugin:test`
Runs Jest against your codebase. See [Tests](#tests) for more details.
Runs Jest against your codebase
Available options:
- `-u, --updateSnapshot` - performs snapshots update
- `--coverage` - reports code coverage
- `--watch` - runs tests in interactive watch mode
- `--coverage` - reports code coverage
- `-u`, `--updateSnapshot` - performs snapshots update
- `--testNamePattern=<regex>` - runs test with names that match provided regex (https://jestjs.io/docs/en/cli#testnamepattern-regex)
- `--testPathPattern=<regex>` - runs test with paths that match provided regex (https://jestjs.io/docs/en/cli#testpathpattern-regex)
#### `grafana-toolkit plugin:dev`
Compiles plugin in development mode.
Available options:
- `-w, --watch` - runs `plugin:dev` task in watch mode
#### `grafana-toolkit plugin:build`
Compiles plugin in production mode
### Building extensions
`grafana-toolkit plugin:build`
Creates production ready build of your extension
### Typescript
To configure Typescript create `tsconfig.json` file in the root dir of your app. grafana-toolkit comes with default tsconfig located in `packages/grafana-toolkit/src/config/tsconfig.plugin.ts`. In order for Typescript to be able to pickup your source files you need to extend that config as follows:
## FAQ
```json
{
"extends": "./node_modules/@grafana/toolkit/src/config/tsconfig.plugin.json",
"include": ["src"],
"compilerOptions": {
"rootDir": "./src",
"typeRoots": ["./node_modules/@types"]
}
}
```
### What tools does grafana-toolkit use?
grafana-toolkit comes with Typescript, TSLint, Prettier, Jest, CSS and SASS support.
### TSLint
grafana-toolkit comes with default config for TSLint, that's located in `packages/grafana-toolkit/src/config/tslint.plugin.ts`. As for now there is now way to customise TSLint config.
### How to start using grafana-toolkit in my extension?
See [Updating your extension to use grafana-toolkit](#updating-your-extension-to-use-grafana-toolkit)
### Can I use Typescript to develop Grafana extensions?
Yes! grafana-toolkit supports Typescript by default.
### Tests
grafana-toolkit comes with Jest as a test runner. It runs tests according to common config locted in `packages/grafana-toolkit/src/config/jest.plugin.config.ts`.
For now the config is not extendable, but our goal is to enable custom jest config via jest.config or package.json file. This might be required in the future if you want to use i.e. `enzyme-to-json` snapshots serializer. For that particular serializer we can also utilise it's API and add initialisation in the setup files (https://github.com/adriantoine/enzyme-to-json#serializer-in-unit-tests). We need to test that approach first.
### How can I test my extension?
grafana-toolkit comes with Jest as a test runner.
#### Jest setup
We are not opinionated about tool used for implmenting tests. Internally at Grafana we use Enzyme. If you want to configure Enzyme as a testing utility, you need to configure enzyme-adapter-react. To do so, you need to create `[YOUR_APP]/config/jest-setup.ts` file that will provide React/Enzyme setup. Simply copy following code into that file to get Enzyme working with React:
Internally at Grafana we use Enzyme. If you are developing React extension and you want to configure Enzyme as a testing utility, you need to configure `enzyme-adapter-react`. To do so create `[YOUR_EXTENSION]/config/jest-setup.ts` file that will provide necessary setup. Copy the following code into that file to get Enzyme working with React:
```ts
import { configure } from 'enzyme';
@ -80,37 +101,52 @@ import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
```
grafana-toolkit will use that file as Jest's setup file. You can also setup Jest with shims of your needs by creating `jest-shim.ts` file in the same directory: `[YOUR_APP]/config/jest-shim.ts`
You can also setup Jest with shims of your needs by creating `jest-shim.ts` file in the same directory: `[YOUR_EXTENSION]/config/jest-shim.ts`
Adidtionaly, you can also provide additional Jest config via package.json file. For more details please refer to [Jest docs](https://jest-bot.github.io/jest/docs/configuration.html#verbose-boolean). Currently we support following properties:
- [`snapshotSerializers`](https://jest-bot.github.io/jest/docs/configuration.html#snapshotserializers-array-string)
### Can I provide custom setup for Jest?
You can provide Jest config via `package.json` file. For more details please refer to [Jest docs](https://jest-bot.github.io/jest/docs/configuration.html).
Currently we support following Jest config properties:
- [`snapshotSerializers`](https://jest-bot.github.io/jest/docs/configuration.html#snapshotserializers-array-string)
- [`moduleNameMapper`](https://jestjs.io/docs/en/configuration#modulenamemapper-object-string-string)
## Working with CSS & static assets
We support pure css, SASS and CSS in JS approach (via Emotion).
### How can I style my extension?
We support pure CSS, SASS and CSS-in-JS approach (via [Emotion](https://emotion.sh/)).
1. Single css/sass file
#### Single CSS or SASS file
Create your css/sass file and import it in your plugin entry point (typically module.ts):
Create your CSS or SASS file and import it in your plugin entry point (typically `module.ts`):
```ts
import 'path/to/your/css_or_sass
import 'path/to/your/css_or_sass'
```
The styles will be injected via `style` tag during runtime.
Note, that imported static assets will be inlined as base64 URIs. *This can be a subject of change in the future!*
> Note that imported static assets will be inlined as base64 URIs. *This can be subject of change in the future!*
#### Theme specific stylesheets
If you want to provide different stylesheets for dark/light theme, create `dark.[css|scss]` and `light.[css|scss]` files in `src/styles` directory of your plugin. grafana-toolkit will generate theme specific stylesheets that will end up in `dist/styles` directory.
In order for Grafana to pickup up you theme stylesheets you need to use `loadPluginCss` from `@grafana/runtime` package. Typically you would do that in the entrypoint of your extension:
2. Theme specific css/sass files
```ts
import { loadPluginCss } from '@grafana/runtime';
If you want to provide different stylesheets for dark/light theme, create `dark.[css|scss]` and `light.[css|scss]` files in `src/styles` directory of your plugin. Based on that we will generate stylesheets that will end up in `dist/styles` directory.
loadPluginCss({
dark: 'plugins/<YOUR-EXTENSION-NAME>/styles/dark.css',
light: 'plugins/<YOUR-EXTENSION-NAME>/styles/light.css',
});
```
TODO: add note about loadPluginCss
You need to add `@grafana/runtime` to your extension dependencies by running `yarn add @grafana/runtime` or `npm instal @grafana/runtime`
Note that static files (png, svg, json, html) are all copied to dist directory when the plugin is bundled. Relative paths to those files does not change.
> Note that in this case static files (png, svg, json, html) are all copied to dist directory when the plugin is bundled. Relative paths to those files does not change!
3. Emotion
#### Emotion
Starting from Grafana 6.2 our suggested way of styling plugins is by using [Emotion](https://emotion.sh). It's a css-in-js library that we use internaly at Grafana. The biggest advantage of using Emotion is that you will get access to Grafana Theme variables.
Starting from Grafana 6.2 *our suggested way* for styling plugins is by using [Emotion](https://emotion.sh). It's a CSS-in-JS library that we use internally at Grafana. The biggest advantage of using Emotion is that you will get access to Grafana Theme variables.
To use start using Emotion you first need to add it to your plugin dependencies:
@ -120,22 +156,45 @@ To use start using Emotion you first need to add it to your plugin dependencies:
Then, import `css` function from emotion:
```import { css } from 'emotion'```
```ts
import { css } from 'emotion'
```
And start implementing your styles:
Now you are ready to implement your styles:
```tsx
const MyComponent = () => {
return <div className={css`background: red;`} />
}
```
To learn more about using Grafana theme please refer to [Theme usage guide](https://github.com/grafana/grafana/blob/master/style_guides/themes.md#react)
> We do not support Emotion's `css` prop. Use className instead!
### Can I adjust Typescript configuration to suit my needs?
Yes! However, it's important that your `tsconfig.json` file contains the following lines:
```json
{
"extends": "./node_modules/@grafana/toolkit/src/config/tsconfig.plugin.json",
"include": ["src"],
"compilerOptions": {
"rootDir": "./src",
"typeRoots": ["./node_modules/@types"]
}
}
```
Using themes: TODO, for now please refer to [internal guide](../../style_guides/themes.md)
### Can I adjust TSLint configuration to suit my needs?
grafana-toolkit comes with [default config for TSLint](https://github.com/grafana/grafana/blob/master/packages/grafana-toolkit/src/config/tslint.plugin.json). As for now there is now way to customise TSLint config.
> NOTE: We do not support Emotion's `css` prop. Use className instead!
## Prettier
When `plugin:build` task is performed we run Prettier check. In order for your IDE to pickup our Prettier config we suggest creating `.prettierrc.js` file in the root directory of your plugin with following contents:
### How is Prettier integrated into grafana-toolkit workflow?
When building extension with [`grafana-toolkit plugin:build`](#building-extensions) task, grafana-toolkit performs Prettier check. If the check detects any Prettier issues, the build will not pass. To avoid such situation we suggest developing plugin with [`grafana-toolkit plugin:dev --watch`](#developing-extensions) task running. This task tries to fix Prettier issues automatically.
### My editor does not respect Prettier config, what should I do?
In order for your editor to pickup our Prettier config you need to create `.prettierrc.js` file in the root directory of your plugin with following content:
```js
module.exports = {
@ -143,9 +202,13 @@ module.exports = {
};
```
## Contributing to grafana-toolkit
Typically plugins should be developed using the `@grafana/toolkit` installed from npm. However, when working on the toolkit, you may want to use the local version. To do that follow the steps below:
1. Clone [Grafana repository](https://github.com/grafana/grafana)
2. Navigate to the directory you have cloned Grafana repo to and run `yarn install --pure-lockfile`
3. Navigate to `<GRAFANA_DIR>/packages/grafana-toolkit` and run `yarn link`
2. Navigate to your plugin directory and run `npx grafana-toolkit plugin:dev --yarnlink`. This will add all dependencies required by grafana-toolkit to your project as well as link your local grafana-toolkit version to be used by the plugin.
## Development mode [todo]
`grafana-toolkit plugin:dev [--watch]`
TODO
- Enable rollup watch on extension sources

@ -1,43 +1,37 @@
## Core changes
JS is the primary source of theme variables for Grafana. Theme definitions are located in `@grafana/ui/themes` directory.
JS is the primary source of theme variables for Grafana. Theme definitions are located in `packages/grafana-ui/src/themes` directory.
#### Themes are implemented in pure js.
This is because our goal is to share variables between app and SASS. To achieve that themes are necessary during build time to be exposed to sass loader via `node-sass` functions (https://github.com/sass/node-sass/blob/master/README.md#functions--v300---experimental). This retrieval is implemented in `getThemeVariable(variablePath, themeName)`.
That's because our goal is to share variables between Grafana app and SASS files.
#### Themes are available to React components via `ThemeContext`
Context is available via `import { ThemeContext } from '@grafana/ui';`
ThemeContext is available via `import { ThemeContext } from '@grafana/ui';`
**If you skip `themeName` param, then dark theme's variant will be used**
## Using themes in Grafana's React components
## Using themes in Grafana
### SASS
`getThemeVariable` is a function, that's available in sass files. Use it i.e. like this:
#### Using `ThemeContext` directly
```scss
// In theme agnostic SASS file
.foo {
font-size: getThemeVariable('typography.size.m');
}
```ts
import { ThemeContext } from '@grafana/ui';
// In *.[themeName].scss
.bar {
background-color: getThemeVariable('colors.blueLight', '[themeName]');
}
<ThemeContext.Consumer>{theme => <Foo theme={theme} />}</ThemeContext.Consumer>;
```
### React
#### Using `ThemeContext` directly
or
```ts
import React, { useContext } from 'react';
import { ThemeContext } from '@grafana/ui';
<ThemeContext.Consumer>{theme => <Foo theme={theme} />}</ThemeContext.Consumer>;
const Foo: React.FunctionComponent<FooProps> = () => {
const theme = useContext(ThemeContext);
// Your component has access to the theme variables now
}
```
#### Using `withTheme` HOC
@ -79,7 +73,7 @@ BarStories.add('Story' () => {
### Angular
There should be very few cases when theme would be used in Angular context. For this purpise there is a function available that retrieves current theme: `import { getCurrentTheme } from app/core/utils/ConfigProvider`
There should be very few cases where theme would be used in Angular context. For this purpise there is a function available that retrieves current theme: `import { getCurrentTheme } from app/core/utils/ConfigProvider`
## Limitations

Loading…
Cancel
Save