diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx
index 2ea8d3f1dd..a38159a258 100644
--- a/packages/app/src/index.tsx
+++ b/packages/app/src/index.tsx
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+// eslint-disable-next-line monorepo/no-internal-import
+import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
diff --git a/packages/cli/src/commands/plugin/assets.d.ts b/packages/cli/asset-types/asset-types.d.ts
similarity index 83%
rename from packages/cli/src/commands/plugin/assets.d.ts
rename to packages/cli/asset-types/asset-types.d.ts
index 34bb6acb70..1763d256f5 100644
--- a/packages/cli/src/commands/plugin/assets.d.ts
+++ b/packages/cli/asset-types/asset-types.d.ts
@@ -14,16 +14,12 @@
* limitations under the License.
*/
+/* eslint-disable import/no-extraneous-dependencies */
+
///
///
///
-declare namespace NodeJS {
- interface ProcessEnv {
- readonly NODE_ENV: 'development' | 'production' | 'test';
- }
-}
-
declare module '*.bmp' {
const src: string;
export default src;
@@ -54,13 +50,15 @@ declare module '*.webp' {
export default src;
}
+declare module '*.icon.svg' {
+ import { ComponentType } from 'react';
+ import { SvgIconProps } from '@material-ui/core';
+
+ const Icon: ComponentType;
+ export default Icon;
+}
+
declare module '*.svg' {
- import * as React from 'react';
-
- export const ReactComponent: React.FunctionComponent & { title?: string }>;
-
const src: string;
export default src;
}
@@ -94,7 +92,3 @@ declare module '*.module.sass' {
const classes: { readonly [key: string]: string };
export default classes;
}
-
-declare module 'rollup-plugin-image-files' {
- export default function image(): any;
-}
diff --git a/packages/cli/asset-types/asset-types.js b/packages/cli/asset-types/asset-types.js
new file mode 100644
index 0000000000..65ef751860
--- /dev/null
+++ b/packages/cli/asset-types/asset-types.js
@@ -0,0 +1,2 @@
+// NOOP, this is just here to unbreak module resolution
+// eslint-disable-next-line notice/notice
diff --git a/packages/cli/asset-types/package.json b/packages/cli/asset-types/package.json
new file mode 100644
index 0000000000..ffa5e09fc1
--- /dev/null
+++ b/packages/cli/asset-types/package.json
@@ -0,0 +1,5 @@
+{
+ "main": "asset-types.js",
+ "types": "asset-types.d.ts",
+ "description": "Provides types for asset files that are handled by the Backstage CLI"
+}
diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js
index ad24976ad0..80e0bcf26c 100644
--- a/packages/cli/config/jest.js
+++ b/packages/cli/config/jest.js
@@ -38,11 +38,16 @@ async function getConfig() {
transform: {
'\\.esm\\.js$': require.resolve('jest-esm-transformer'),
'\\.(js|jsx|ts|tsx)': require.resolve('ts-jest'),
+ '\\.(bmp|gif|jpe|png|frag|xml|svg)': require.resolve(
+ './jestFileTransform.js',
+ ),
},
// Default behaviour is to not apply transforms for node_modules, but we still want
// to apply the esm-transformer to .esm.js files, since that's what we use in backstage packages.
- transformIgnorePatterns: ['/node_modules/(?!.*\\.esm\\.js$)'],
+ transformIgnorePatterns: [
+ '/node_modules/(?!.*\\.(?:esm\\.js|bmp|gif|jpe|png|frag|xml|svg)$)',
+ ],
};
// Use src/setupTests.ts as the default location for configuring test env
diff --git a/packages/cli/config/jestFileTransform.js b/packages/cli/config/jestFileTransform.js
new file mode 100644
index 0000000000..e6ff1895f8
--- /dev/null
+++ b/packages/cli/config/jestFileTransform.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const path = require('path');
+
+module.exports = {
+ process(src, filename) {
+ const assetFilename = JSON.stringify(path.basename(filename));
+
+ if (filename.match(/\.icon\.svg$/)) {
+ return `const React = require('react');
+ const SvgIcon = require('@material-ui/core/SvgIcon').default;
+ module.exports = {
+ __esModule: true,
+ default: props => React.createElement(SvgIcon, props, {
+ $$typeof: Symbol.for('react.element'),
+ type: 'svg',
+ ref: ref,
+ key: null,
+ props: Object.assign({}, props, {
+ children: ${assetFilename}
+ })
+ })
+ };`;
+ }
+
+ return `module.exports = ${assetFilename};`;
+ },
+};
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 96ca8e4a4f..66828e9dec 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -39,6 +39,10 @@
"@rollup/plugin-node-resolve": "^7.1.1",
"@spotify/eslint-config": "^7.0.1",
"@sucrase/webpack-loader": "^2.0.0",
+ "@svgr/plugin-jsx": "4.3.x",
+ "@svgr/plugin-svgo": "4.3.x",
+ "@svgr/rollup": "4.3.x",
+ "@svgr/webpack": "4.3.x",
"@types/start-server-webpack-plugin": "^2.2.0",
"@types/webpack-env": "^1.15.2",
"@types/webpack-node-externals": "^1.7.1",
diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts
index 0cd800f2ea..5f881bd53c 100644
--- a/packages/cli/src/lib/bundler/transforms.ts
+++ b/packages/cli/src/lib/bundler/transforms.ts
@@ -17,6 +17,7 @@
import webpack, { Module, Plugin } from 'webpack';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import { BundlingOptions, BackendBundlingOptions } from './types';
+import { svgrTemplate } from '../svgrTemplate';
type Transforms = {
loaders: Module['rules'];
@@ -46,7 +47,28 @@ export const transforms = (
},
},
{
- test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.frag/, /\.xml/],
+ test: [/\.icon\.svg$/],
+ use: [
+ {
+ loader: require.resolve('@sucrase/webpack-loader'),
+ options: { transforms: ['jsx'] },
+ },
+ {
+ loader: require.resolve('@svgr/webpack'),
+ options: { babel: false, template: svgrTemplate },
+ },
+ ],
+ },
+ {
+ test: [
+ /\.bmp$/,
+ /\.gif$/,
+ /\.jpe?g$/,
+ /\.png$/,
+ /\.frag/,
+ { test: /\.svg/, not: [/\.icon\.svg/] },
+ /\.xml/,
+ ],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
diff --git a/packages/cli/src/lib/packager/config.ts b/packages/cli/src/lib/packager/config.ts
index 30680ef3b9..5987290604 100644
--- a/packages/cli/src/lib/packager/config.ts
+++ b/packages/cli/src/lib/packager/config.ts
@@ -23,12 +23,14 @@ import resolve from '@rollup/plugin-node-resolve';
import postcss from 'rollup-plugin-postcss';
import esbuild from 'rollup-plugin-esbuild';
import imageFiles from 'rollup-plugin-image-files';
+import svgr from '@svgr/rollup';
import dts from 'rollup-plugin-dts';
import json from '@rollup/plugin-json';
import { RollupOptions, OutputOptions } from 'rollup';
import { BuildOptions, Output } from './types';
import { paths } from '../paths';
+import { svgrTemplate } from '../svgrTemplate';
export const makeConfigs = async (
options: BuildOptions,
@@ -89,8 +91,12 @@ export const makeConfigs = async (
exclude: ['**/*.stories.*', '**/*.test.*'],
}),
postcss(),
- imageFiles(),
+ imageFiles({ exclude: '**/*.icon.svg' }),
json(),
+ svgr({
+ include: '**/*.icon.svg',
+ template: svgrTemplate,
+ }),
esbuild({
target: 'es2019',
}),
diff --git a/packages/cli/src/lib/svgrTemplate.ts b/packages/cli/src/lib/svgrTemplate.ts
new file mode 100644
index 0000000000..5f7c7f9a4c
--- /dev/null
+++ b/packages/cli/src/lib/svgrTemplate.ts
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This template, together with loaders in the bundler and packages, allows
+ * for SVG to be imported directly as MUI SvgIcon components by suffixing
+ * them with .icon.svg
+ */
+export function svgrTemplate(
+ { template }: any,
+ _opts: any,
+ { imports, interfaces, componentName, jsx }: any,
+) {
+ const iconName = {
+ ...componentName,
+ name: `${componentName.name.replace(/icon$/, '')}Icon`,
+ };
+
+ const defaultExport = {
+ type: 'ExportDefaultDeclaration',
+ declaration: iconName,
+ };
+
+ const typeScriptTemplate = template.smart({ plugins: ['typescript'] });
+ return typeScriptTemplate.ast`
+${imports}
+import SvgIcon from '@material-ui/core/SvgIcon';
+
+${interfaces}
+
+const ${iconName} = props => React.createElement(SvgIcon, props, ${jsx.children});
+
+${defaultExport}`;
+}
diff --git a/packages/cli/@types/rollup-plugin-image-files.d.ts b/packages/cli/src/types.d.ts
similarity index 65%
rename from packages/cli/@types/rollup-plugin-image-files.d.ts
rename to packages/cli/src/types.d.ts
index 9ddc2c2351..8cb5a1e7df 100644
--- a/packages/cli/@types/rollup-plugin-image-files.d.ts
+++ b/packages/cli/src/types.d.ts
@@ -14,4 +14,16 @@
* limitations under the License.
*/
-declare module 'rollup-plugin-image-files';
+declare namespace NodeJS {
+ interface ProcessEnv {
+ readonly NODE_ENV: 'development' | 'production' | 'test';
+ }
+}
+
+declare module 'rollup-plugin-image-files' {
+ export default function image(options?: any): any;
+}
+
+declare module '@svgr/rollup' {
+ export default function svgr(options?: any): any;
+}
diff --git a/packages/cli/templates/default-app/packages/app/src/index.tsx b/packages/cli/templates/default-app/packages/app/src/index.tsx
index b597a44232..b16aaf7cd2 100644
--- a/packages/cli/templates/default-app/packages/app/src/index.tsx
+++ b/packages/cli/templates/default-app/packages/app/src/index.tsx
@@ -1,3 +1,4 @@
+import '@backstage/cli/asset-types';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
diff --git a/packages/core/src/layout/ErrorPage/MicDrop.jsx b/packages/core/src/layout/ErrorPage/MicDrop.jsx
index 4c4098f486..ca0a0ae0a6 100644
--- a/packages/core/src/layout/ErrorPage/MicDrop.jsx
+++ b/packages/core/src/layout/ErrorPage/MicDrop.jsx
@@ -16,6 +16,7 @@
import React from 'react';
import { makeStyles } from '@material-ui/core';
+import MicDropSvgUrl from './mic-drop.svg';
const useStyles = makeStyles({
micDrop: {
@@ -28,133 +29,5 @@ const useStyles = makeStyles({
export const MicDrop = () => {
const classes = useStyles();
- return (
-
- );
+ return
;
};
diff --git a/packages/core/src/layout/ErrorPage/mic-drop.svg b/packages/core/src/layout/ErrorPage/mic-drop.svg
new file mode 100644
index 0000000000..adc027b551
--- /dev/null
+++ b/packages/core/src/layout/ErrorPage/mic-drop.svg
@@ -0,0 +1,126 @@
+
diff --git a/plugins/graphiql/src/assets/graphiql.icon.svg b/plugins/graphiql/src/assets/graphiql.icon.svg
new file mode 100644
index 0000000000..66aee7be5a
--- /dev/null
+++ b/plugins/graphiql/src/assets/graphiql.icon.svg
@@ -0,0 +1,64 @@
+
diff --git a/plugins/graphiql/src/route-refs.tsx b/plugins/graphiql/src/route-refs.tsx
index 5ddd81d55d..3e8d1d3a9c 100644
--- a/plugins/graphiql/src/route-refs.tsx
+++ b/plugins/graphiql/src/route-refs.tsx
@@ -14,76 +14,8 @@
* limitations under the License.
*/
-import React, { FC } from 'react';
import { createRouteRef } from '@backstage/core';
-import { SvgIcon, SvgIconProps } from '@material-ui/core';
-
-const GraphiQLIcon: FC = props => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-);
+import GraphiQLIcon from './assets/graphiql.icon.svg';
export const graphiQLRouteRef = createRouteRef({
icon: GraphiQLIcon,
diff --git a/yarn.lock b/yarn.lock
index 479c4d0e8c..da47a9bd86 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3208,7 +3208,7 @@
dependencies:
"@babel/types" "^7.4.4"
-"@svgr/plugin-jsx@^4.3.3":
+"@svgr/plugin-jsx@4.3.x", "@svgr/plugin-jsx@^4.3.3":
version "4.3.3"
resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz#e2ba913dbdfbe85252a34db101abc7ebd50992fa"
integrity sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w==
@@ -3218,7 +3218,7 @@
"@svgr/hast-util-to-babel-ast" "^4.3.2"
svg-parser "^2.0.0"
-"@svgr/plugin-svgo@^4.3.1":
+"@svgr/plugin-svgo@4.3.x", "@svgr/plugin-svgo@^4.3.1":
version "4.3.1"
resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz#daac0a3d872e3f55935c6588dd370336865e9e32"
integrity sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w==
@@ -3227,7 +3227,21 @@
merge-deep "^3.0.2"
svgo "^1.2.2"
-"@svgr/webpack@^4.0.3":
+"@svgr/rollup@4.3.x":
+ version "4.3.3"
+ resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-4.3.3.tgz#db8bc2746ae0930c14cba2409f417a6ac6aadb38"
+ integrity sha512-YwgnXN8xPRYFhkfoTUiZktjkjolthaK/lz0okzU09VcBvjx08R7yK1IEwXH3c98sMn8ORdNdiy4Qox78CMjljg==
+ dependencies:
+ "@babel/core" "^7.4.5"
+ "@babel/plugin-transform-react-constant-elements" "^7.0.0"
+ "@babel/preset-env" "^7.4.5"
+ "@babel/preset-react" "^7.0.0"
+ "@svgr/core" "^4.3.3"
+ "@svgr/plugin-jsx" "^4.3.3"
+ "@svgr/plugin-svgo" "^4.3.1"
+ rollup-pluginutils "^2.8.1"
+
+"@svgr/webpack@4.3.x", "@svgr/webpack@^4.0.3":
version "4.3.3"
resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017"
integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg==
@@ -16612,7 +16626,7 @@ rollup-pluginutils@2.4.1:
estree-walker "^0.6.0"
micromatch "^3.1.10"
-rollup-pluginutils@2.8.2, rollup-pluginutils@^2.8.2:
+rollup-pluginutils@2.8.2, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2:
version "2.8.2"
resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e"
integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==