Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mayflower v10: Replace SVG Sprite Loader with SVGR Icons #1123

Merged
merged 18 commits into from
Jul 27, 2020
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ node_modules
!react/.env
# Distribution folder
dist
# Ignore yalc files used for linking projects in dev.
yalc.lock
.yalc
6 changes: 6 additions & 0 deletions changelogs/DP-19414.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Changed:
- project: React
component: Icon
description: Icon has been refactored from one component into many icon components. Each .svg icon file is now generated into its own React component at build time with SVGR and SVG Sprite Loader is no longer used.
clairesunstudio marked this conversation as resolved.
Show resolved Hide resolved
issue: DP-19414
impact: Major
3 changes: 2 additions & 1 deletion react/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ umd/
src/index.js
src/**/*.stories.js
src/**/*.knob*
gulpfile.js
gulpfile.js
icon-template.js
52 changes: 26 additions & 26 deletions react/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,32 @@
},
"settings": {
"import/resolver": {
"alias": {
"map": [
["MayflowerReactComponents", "./src/components"],
["MayflowerReactAtoms", "./src/components/atoms"],
["MayflowerReactAnimations", "./src/components/animations"],
["MayflowerReactButtons", "./src/components/atoms/buttons"],
["MayflowerReactContact", "./src/components/atoms/contact"],
["MayflowerReactDivider", "./src/components/atoms/Divider"],
["MayflowerReactHeadings", "./src/components/atoms/headings"],
["MayflowerReactLinks", "./src/components/atoms/links"],
["MayflowerReactLists", "./src/components/atoms/lists"],
["MayflowerReactMedia", "./src/components/atoms/media"],
["MayflowerReactPlaceholder", "./src/components/atoms/Placeholder"],
["MayflowerReactTable", "./src/components/atoms/table"],
["MayflowerReactText", "./src/components/atoms/text"],
["MayflowerReactBase", "./src/components/base"],
["MayflowerReactDataviz", "./src/components/dataviz"],
["MayflowerReactForms", "./src/components/forms"],
["MayflowerReactMolecules", "./src/components/molecules"],
["MayflowerReactOrganisms", "./src/components/organisms"],
["MayflowerReactPages", "./src/components/pages"],
["MayflowerReactTemplates", "./src/components/templates"],
["MayflowerReactUtilities", "./src/components/utilities"],
["MayflowerReactGenTeaser", "./src/components/organisms/GenTeaser"],
["SharedAssets", "@massds/mayflower-assets/static"]
],
"babel-module": {
"alias": {
"MayflowerReactComponents": "./src/components",
"MayflowerReactAtoms": "./src/components/atoms",
"MayflowerReactAnimations": "./src/components/animations",
"MayflowerReactButtons": "./src/components/atoms/buttons",
"MayflowerReactContact": "./src/components/atoms/contact",
"MayflowerReactDivider": "./src/components/atoms/Divider",
"MayflowerReactHeadings": "./src/components/atoms/headings",
"MayflowerReactLinks": "./src/components/atoms/links",
"MayflowerReactLists": "./src/components/atoms/lists",
"MayflowerReactMedia": "./src/components/atoms/media",
"MayflowerReactPlaceholder": "./src/components/atoms/Placeholder",
"MayflowerReactTable": "./src/components/atoms/table",
"MayflowerReactText": "./src/components/atoms/text",
"MayflowerReactBase": "./src/components/base",
"MayflowerReactDataviz": "./src/components/dataviz",
"MayflowerReactForms": "./src/components/forms",
"MayflowerReactMolecules": "./src/components/molecules",
"MayflowerReactOrganisms": "./src/components/organisms",
"MayflowerReactPages": "./src/components/pages",
"MayflowerReactTemplates": "./src/components/templates",
"MayflowerReactUtilities": "./src/components/utilities",
"MayflowerReactGenTeaser": "./src/components/organisms/GenTeaser",
"SharedAssets": "@massds/mayflower-assets/static"
},
"extensions": [".js", ".jsx"]
}
}
Expand Down
7 changes: 7 additions & 0 deletions react/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ backstop/data/*report/

.DS_Store
**/.DS_Store
src/components/base/Icon/**
!src/components/base/Icon/assets
!src/components/base/Icon/assets/**
!src/components/base/Icon/Icon.stories.js
!src/components/base/Icon/IconDisplay.js
!src/components/base/Icon/Icon.knob.options.js
!src/components/base/Icon/_icon-display.scss
22 changes: 20 additions & 2 deletions react/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const path = require('path');
const assets = require('@massds/mayflower-assets');
const iconPath = path.resolve(__dirname, '../src/components/base/Icon/assets');

module.exports = {
stories: ['../src/**/*.stories.js'],
addons: [
Expand All @@ -26,15 +28,31 @@ module.exports = {
}
},
],
webpackFinal: async (config, { configType }) => {

webpackFinal: (config, { configType }) => {
// modify storybook's file-loader rule to avoid conflicts with svgr
const fileLoaderRule = config.module.rules.find(rule => rule.test.test && rule.test.test('.svg'));
fileLoaderRule.exclude = iconPath;
// Configure the storysource plugin.
config.module.rules.push({
test: /\.stories\.js?$/,
loader: require.resolve('@storybook/addon-storysource/loader'),
enforce: 'pre',
});

config.module.rules.unshift({
test: /\.svg$/,
include: iconPath,
use: [
{
loader: '@svgr/webpack',
options: {
icon: true,
outDir: './src/components/base/Icon'
},
},
],
});

config.resolve = {
...config.resolve,
alias: {
Expand Down
10 changes: 10 additions & 0 deletions react/.svgrrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
"icon": true,
"svgoConfig": {
"removeXMLNS": true
},
"plugins": ["@svgr/plugin-svgo", "@svgr/plugin-jsx"],
"ext": "mjs",
"prettier": false,
"template": require('./icon-template'),
}
14 changes: 12 additions & 2 deletions react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ $ `npm test`: Starts Jest test suite in watch mode

$ `npm run test:coverage` Generates a test report

$ `npm run build`: Compile the code from /src into es6 and commonjs formats in preparation for publishing.
$ `npm run build`: Compile the code from `/src` into es6 and commonjs formats in preparation for publishing. This command also generates icon components from the .svg files under `/src/components/base/Icon/assets` to `dist/Icon`.


#### Adding dependencies

Expand All @@ -88,6 +89,11 @@ $ ``git add package.json package-lock.json``

$ ``git commit -m 'Added purgecss library'``

#### Icon Component Generation
Mayflower React's SVG icon components are generated using [SVGR](https://react-svgr.com/) at build time for both development and production modes. Currently, the `.svg` files under `src/components/base/Icon/assets` are generated into React components. When icon components are generated for production, both ES6 and CommonJS versions of the components are created using babel.

A custom template used by SVGR to create the icon component files can be found within `icon-template.js`. SVGR itself is configured using `.svgrrc.js`.

## Mayflower-React Testing

#### Production build testing
Expand All @@ -114,7 +120,11 @@ $ ``source-map-explorer umd/@massds/*.min.js``

#### Testing unpublished Mayflower React components

Sometimes it is useful to test a Mayflower React component that has not yet been published to npm. This can be accomplished by using the [``npm link``](https://docs.npmjs.com/cli/link) command.
If you're developing on Mayflower React and want to test your changes on another project (such as Gatsby, Next.JS, Create React App, etc), we recommend using [yalc](https://github.com/whitecolor/yalc) instead of `npm link` or `yarn link`, as Node dependency resolution issues may arise.

To use yalc:
1. Run `yalc publish` in the `react/` directory. This will run Mayflower React's build script and store the build version of the package under your yalc global directory.
2. Run `yalc link @massds/mayflower-react` in your other project. Mayflower React will now be installed and pointing to the version from step 1.


## Mayflower-React Release Process
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
163 changes: 157 additions & 6 deletions react/gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ const babel = require('gulp-babel');
const rename = require('gulp-rename');
const del = require('del');
const path = require('path');

const run = require('gulp-run-command').default;
function clean() {
return del(['dist']);
}

function styles() {
return src(['./src/components/**/*.scss'])
return src(['./src/components/**/*.scss', '!src/components/**/Icon/**'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment for this path?

.pipe(rename((p) => {
const splitPath = p.dirname.split('/');
// eslint-disable-next-line no-param-reassign
Expand All @@ -25,6 +25,135 @@ function icons() {
.pipe(dest('dist/Icon/assets'));
}

function transpileES5Icons() {
return src('./dist/Icon/*.mjs')
.pipe(rename((p) => {
const splitPath = p.dirname.split('/');
// eslint-disable-next-line no-param-reassign
p.dirname = splitPath[splitPath.length - 1];
}))
.pipe(babel({
presets: [
[
'@babel/preset-env',
{
loose: true,
modules: 'commonjs'
}
],
[
'@babel/preset-react',
{
development: false
}
],
[
'babel-preset-proposals',
{
loose: true,
decorators: true,
classProperties: true,
exportDefaultFrom: true,
exportNamespaceFrom: true,
absolutePaths: true
}
]
],
plugins: [
[
'module-resolver',
{
resolvePath,
alias: aliases,
isES5: true
}
],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
[
'babel-plugin-transform-react-remove-prop-types',
{
mode: 'wrap'
}
],
[
'@babel/plugin-transform-runtime',
{
absoluteRuntime: false,
useESModules: false,
helpers: false
}
],
'babel-plugin-add-module-exports'
]
}))
.pipe(dest('dist/Icon'));
}

function transpileES6Icons() {
return src('./dist/Icon/*.mjs', '!./dist/Icon/index.mjs')
.pipe(babel({
presets: [
[
'@babel/preset-env',
{
loose: true,
modules: false,
exclude: [
'transform-block-scoping',
'transform-arrow-functions',
'transform-function-name'
]
}
],
[
'@babel/preset-react',
{
development: false,
}
],
],
plugins: [
[
'module-resolver',
{
resolvePath,
alias: aliases,
isES5: false
}
],
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
[
'babel-plugin-transform-react-remove-prop-types',
{
mode: 'wrap'
}
],
[
'@babel/plugin-transform-runtime',
{
absoluteRuntime: false,
useESModules: true,
helpers: false
}
]
]
}))
.pipe(rename((p) => {
const splitPath = p.dirname.split('/');
// eslint-disable-next-line no-param-reassign
p.dirname = splitPath[splitPath.length - 1];
// eslint-disable-next-line no-param-reassign
p.extname = '.mjs';
}))
.pipe(dest('dist/Icon'));
}

async function generateIcons() {
return run('svgr --out-dir ./dist/Icon ./src/components/base/Icon/assets --config-file=./.svgrrc.js')()
}

const aliases = {
'MayflowerReactGenTeaser/(.*)$': './\\1',
'MayflowerReactComponents/(.*)$': './\\1',
Expand Down Expand Up @@ -56,7 +185,7 @@ const sources = [
'!src/**/*.knobs.options.js',
'!src/**/*.knob.options.js',
'!src/**/Colors/**',
'!src/**/storyutils.js'
'!src/**/Icon/**'
];

function resolvePath(sourcePath, currentFile, opts) {
Expand All @@ -82,7 +211,8 @@ function resolvePath(sourcePath, currentFile, opts) {
'TabContainer/context',
'utilities/componentPropTypeCheck',
'Breadcrumb/item',
'GenTeaser/utils'
'GenTeaser/utils',
'Base/Icon/',
];
// If the current path is a file and not a directory...
if (excludes.some((rule) => sourcePath.includes(rule))) {
Expand Down Expand Up @@ -170,7 +300,12 @@ function transpileES6() {
'@babel/preset-env',
{
loose: true,
modules: false
modules: false,
exclude: [
'transform-block-scoping',
'transform-arrow-functions',
'transform-function-name'
]
}
],
[
Expand Down Expand Up @@ -227,4 +362,20 @@ function transpileES6() {
}))
.pipe(dest('dist'));
}
exports.default = series(clean, parallel(transpileES5, transpileES6, styles, icons));

function cleanIconDir() {
return del([
'src/components/base/Icon/*',
'!src/components/base/Icon/assets',
'!src/components/base/Icon/IconDisplay.js',
'!src/components/base/Icon/Icon.stories.js',
'!src/components/base/Icon/Icon.knob.options.js',
'!src/components/base/Icon/_icon-display.scss'
]);
}

exports.cleanIconDir = cleanIconDir;
exports.generateIcons = generateIcons;
exports.transpileES5Icons = transpileES5Icons;
exports.transpileES6Icons = transpileES6Icons;
exports.default = series(clean, parallel(transpileES5, transpileES6, styles, series(generateIcons, transpileES5Icons, transpileES6Icons)));
Loading