From 554369d2c14c67e100fe393b7f73f46d70e12e59 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 23 Jun 2020 09:24:38 +0200 Subject: [PATCH 1/5] cli: provide global asset module types through separate import --- packages/app/src/index.tsx | 2 ++ .../asset-types.d.ts} | 18 ++---------------- packages/cli/asset-types/asset-types.js | 2 ++ packages/cli/asset-types/package.json | 5 +++++ .../types.d.ts} | 14 +++++++++++++- .../default-app/packages/app/src/index.tsx | 1 + 6 files changed, 25 insertions(+), 17 deletions(-) rename packages/cli/{src/commands/plugin/assets.d.ts => asset-types/asset-types.d.ts} (83%) create mode 100644 packages/cli/asset-types/asset-types.js create mode 100644 packages/cli/asset-types/package.json rename packages/cli/{@types/rollup-plugin-image-files.d.ts => src/types.d.ts} (65%) 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..d8995fcb37 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; @@ -55,12 +51,6 @@ declare module '*.webp' { } declare module '*.svg' { - import * as React from 'react'; - - export const ReactComponent: React.FunctionComponent & { title?: string }>; - const src: string; export default src; } @@ -94,7 +84,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/@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'; From 747acd2dfcf614d9cff085e0d9b69e2f93fc52d8 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 23 Jun 2020 09:26:05 +0200 Subject: [PATCH 2/5] cli: allow svg imports and special .icon.svg import --- packages/cli/asset-types/asset-types.d.ts | 8 ++++ packages/cli/package.json | 4 ++ packages/cli/src/lib/bundler/transforms.ts | 24 ++++++++++- packages/cli/src/lib/packager/config.ts | 8 +++- packages/cli/src/lib/svgrTemplate.ts | 47 ++++++++++++++++++++++ yarn.lock | 22 ++++++++-- 6 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 packages/cli/src/lib/svgrTemplate.ts diff --git a/packages/cli/asset-types/asset-types.d.ts b/packages/cli/asset-types/asset-types.d.ts index d8995fcb37..1763d256f5 100644 --- a/packages/cli/asset-types/asset-types.d.ts +++ b/packages/cli/asset-types/asset-types.d.ts @@ -50,6 +50,14 @@ 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' { const src: string; export default src; 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/yarn.lock b/yarn.lock index fd351efe36..3aa425b46e 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== @@ -16470,7 +16484,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== From 13dab6fd64785aa44115540aae73772b76b145ca Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 23 Jun 2020 09:26:35 +0200 Subject: [PATCH 3/5] core: move error page MicDrop out as separate svg file --- .../core/src/layout/ErrorPage/MicDrop.jsx | 131 +----------------- .../core/src/layout/ErrorPage/mic-drop.svg | 126 +++++++++++++++++ 2 files changed, 128 insertions(+), 129 deletions(-) create mode 100644 packages/core/src/layout/ErrorPage/mic-drop.svg 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 @@ + + + + + + + + + + + + + + + + + + + + + From 6f43bc4c0531284e10ef8b87b26a9171a1fb557a Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 23 Jun 2020 09:27:06 +0200 Subject: [PATCH 4/5] plugins/graphiql: move graphiql icon out as separate icon svg --- plugins/graphiql/src/assets/graphiql.icon.svg | 64 +++++++++++++++++ plugins/graphiql/src/route-refs.tsx | 70 +------------------ 2 files changed, 65 insertions(+), 69 deletions(-) create mode 100644 plugins/graphiql/src/assets/graphiql.icon.svg 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, From d4cc7c107fd2d1caeed8b4d4bde55532e69ed6b9 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 23 Jun 2020 10:18:42 +0200 Subject: [PATCH 5/5] cli: added jest transform for static assets --- packages/cli/config/jest.js | 7 +++- packages/cli/config/jestFileTransform.js | 42 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 packages/cli/config/jestFileTransform.js 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};`; + }, +};