From eee84b0edfeb5de34207cf6885c4d3884539c367 Mon Sep 17 00:00:00 2001 From: Eric Fennis Date: Sat, 18 Jul 2020 00:52:09 +0200 Subject: [PATCH] Add build scripts for dist --- package.json | 34 ++++++++------- scripts/build/generateExportsFile.js | 31 ++++++++++++++ scripts/build/generateIconFiles.js | 9 +++- scripts/build/generateReactFile.js | 43 ------------------- scripts/build/generateVueFile.js | 0 scripts/build/helpers.js | 10 +++++ scripts/buildIcons.js | 19 +++++---- scripts/optimizeSvgs.js | 16 +++++++ scripts/render/processSvg.js | 58 ++++++++++++++++++++++++++ src/{ => getters}/getElement.js | 0 src/{ => getters}/getReactComponent.js | 0 src/{ => getters}/getVueComponent.js | 0 src/icons/.gitkeep | 0 13 files changed, 151 insertions(+), 69 deletions(-) create mode 100644 scripts/build/generateExportsFile.js delete mode 100644 scripts/build/generateReactFile.js delete mode 100644 scripts/build/generateVueFile.js create mode 100644 scripts/optimizeSvgs.js create mode 100644 scripts/render/processSvg.js rename src/{ => getters}/getElement.js (100%) rename src/{ => getters}/getReactComponent.js (100%) rename src/{ => getters}/getVueComponent.js (100%) delete mode 100644 src/icons/.gitkeep diff --git a/package.json b/package.json index 98f7de4c8..100adff2a 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,43 @@ { + "name": "featherity", + "amdName": "featherity", + "version": "1.0.0", "private": true, + "main": "dist/main.js", + "module": "dist/main.module.js", + "umd:main": "dist/main.umd.js", + "unpkg": "dist/main.min.js", + "source": "src/index.js", + "exports": { + ".": { + "browser": "./dist/main.module.js", + "umd": "./dist/main.umd.js", + "import": "./dist/main.mjs", + "require": "./dist/main.js" + } + }, "scripts": { - "react:compile": "yarn workspace react compile", "build": "npx babel-node ./scripts/buildIcons.js", - "start": "babel-watch ./src/buildIcons.js" + "optimize": "npx babel-node ./scripts/optimizeSvgs.js" }, - "workspaces": [ - "packages/react" - ], "devDependencies": { "@babel/core": "^7.10.5", - "@commitlint/cli": "^5.2.5", - "@commitlint/config-conventional": "^6.1.3", - "algoliasearch": "^3.27.1", "babel-cli": "^6.24.1", "babel-loader": "^7.1.1", "babel-preset-env": "^1.7.0", "babel-preset-stage-2": "^6.24.1", "babel-watch": "^7.0.0", "cheerio": "^1.0.0-rc.2", - "commitizen": "^2.9.6", - "cz-conventional-changelog": "^2.1.0", "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-config-prettier": "^2.9.0", "eslint-plugin-import": "^2.5.0", "eslint-plugin-prettier": "^2.5.0", "html-minifier": "^3.5.8", - "husky": "^0.14.3", - "jest": "^22.4.4", "lint-staged": "^6.0.0", - "npm-run-all": "^4.1.2", "prettier": "^1.8.2", "semantic-release": "^12.2.2", - "svgo": "^0.7.2", - "webpack": "^4.8.3", - "webpack-cli": "^2.1.3" + "svgo": "^0.7.2" }, "dependencies": { "htmlparser2": "^4.1.0" diff --git a/scripts/build/generateExportsFile.js b/scripts/build/generateExportsFile.js new file mode 100644 index 000000000..adf8d6396 --- /dev/null +++ b/scripts/build/generateExportsFile.js @@ -0,0 +1,31 @@ +import { generateComponentName, resetFile, writeFile} from './helpers'; + +export default function(fileName, outputDirectory, componentGetter, iconVNodesObject) { + // Reset file + resetFile(fileName, outputDirectory); + + // Import the component getter + writeFile(`import ${componentGetter} from './src/getters/${componentGetter}';\n\n`, fileName, outputDirectory); + + const icons = Object.keys(iconVNodesObject); + + // Generate Import for Icon VNodes + icons.forEach(iconName => { + const componentName = generateComponentName(iconName); + const importString = `import ${componentName}VNode from './icons';\n`; + writeFile(importString, fileName, outputDirectory); + }); + + writeFile('\n', fileName, outputDirectory); + + // Generate export for all the icons + // + // output: export const myIcon = getComponent(myIconVNode); + icons.forEach(iconName => { + const componentName = generateComponentName(iconName); + const constantString = `export const ${componentName} = ${componentGetter}(${componentName}VNode);\n`; + writeFile(constantString, fileName, outputDirectory); + }); + + console.log(`Successfully generated ${fileName} file`); +} diff --git a/scripts/build/generateIconFiles.js b/scripts/build/generateIconFiles.js index a600e19b2..04915c5ce 100644 --- a/scripts/build/generateIconFiles.js +++ b/scripts/build/generateIconFiles.js @@ -3,12 +3,17 @@ import path from 'path'; import prettier from 'prettier'; import { generateComponentName } from './helpers'; -export default function(iconVNodesObject) { +export default function(iconVNodesObject, outputDirectory) { const icons = Object.keys(iconVNodesObject); + const iconsDistDirectory = path.join(outputDirectory, `icons`); + + if (!fs.existsSync(iconsDistDirectory)){ + fs.mkdirSync(iconsDistDirectory); + } icons.forEach(icon => { - const location = path.join(process.cwd(), "src/icons", `${icon}.js`); + const location = path.join(iconsDistDirectory, `${icon}.js`); const ComponentName = generateComponentName(icon); const VNode = JSON.stringify(iconVNodesObject[icon]); diff --git a/scripts/build/generateReactFile.js b/scripts/build/generateReactFile.js deleted file mode 100644 index 0bcd16a95..000000000 --- a/scripts/build/generateReactFile.js +++ /dev/null @@ -1,43 +0,0 @@ - -import fs from 'fs'; -import path from 'path'; -import prettier from 'prettier'; - -import { generateComponentName } from './helpers'; - -const FILE_NAME = "react.js"; - -const resetFile = fs.writeFileSync(path.join(process.cwd(), FILE_NAME), "", "utf-8"); -const writeFile = (content) => fs.appendFileSync( - path.join(process.cwd(), FILE_NAME), - content, - "utf-8" -); - -export default function(iconVNodesObject) { - - writeFile(); - writeFile(`import getReactComponent from './src/getReactComponent';\n`); - - // const componentName = generateComponentName(icon); - const icons = Object.keys(iconVNodesObject); - - // icons.forEach(iconName => { - // const constantString = `const ${componentName} = getReactComponent();\n`; - // const exportString = `export ${componentName};\n`; - - - // }); - - // icons.forEach(iconName => { - // const constantString = `const ${componentName} = getReactComponent();\n`; - // const exportString = `export ${componentName};\n`; - - - // }); - - const exportStringNames = icons.map(iconName => generateComponentName(iconName)).join(",\n"); - const exportString = `export { ${exportStringNames} };\n`; - - writeFile(exportString); -} diff --git a/scripts/build/generateVueFile.js b/scripts/build/generateVueFile.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/scripts/build/helpers.js b/scripts/build/helpers.js index 2e223e4e0..dea0017bb 100644 --- a/scripts/build/helpers.js +++ b/scripts/build/helpers.js @@ -1,4 +1,6 @@ import upperCamelCase from 'upperCamelCase'; +import fs from 'fs'; +import path from 'path'; /** * Generates a componentName of a String. @@ -6,3 +8,11 @@ import upperCamelCase from 'upperCamelCase'; * @param {string} iconName */ export const generateComponentName = (iconName) => iconName === "github" ? "GitHub" : upperCamelCase(iconName); + +export const resetFile = (fileName, outputDirectory) => fs.writeFileSync(path.join(outputDirectory, fileName), "", "utf-8"); + +export const writeFile = (content, fileName, outputDirectory) => fs.appendFileSync( + path.join(outputDirectory, fileName), + content, + "utf-8" +); diff --git a/scripts/buildIcons.js b/scripts/buildIcons.js index 9c123f8ea..26557b717 100644 --- a/scripts/buildIcons.js +++ b/scripts/buildIcons.js @@ -4,20 +4,23 @@ import path from 'path'; import renderIconsObject from './render/renderIconsObject'; import renderIconVNodes from './render/renderIconVNodes'; import generateIconFiles from './build/generateIconFiles'; -import generateReactFile from './build/generateReactFile'; - - +import generateExportsFile from './build/generateExportsFile'; const IN_DIR = path.resolve(__dirname, '../icons'); -// const OUT_FILE = path.resolve(__dirname, '../dist/icons.json'); +const OUTPUT_DIR = path.resolve(__dirname, '../src'); -// console.log(`Building ${OUT_FILE}...`); +if (!fs.existsSync(OUTPUT_DIR)){ + fs.mkdirSync(OUTPUT_DIR); +} const svgFiles = fs.readdirSync(IN_DIR).filter(file => path.extname(file) === '.svg'); const getSvg = svgFile => fs.readFileSync(path.join(IN_DIR, svgFile)); const icons = renderIconsObject(svgFiles, getSvg); -const iconVnodes = renderIconVNodes(icons); +const iconVNodes = renderIconVNodes(icons); -// generateIconFiles(iconVnodes); -generateReactFile(iconVnodes); +generateIconFiles(iconVNodes, OUTPUT_DIR); + +generateExportsFile('index.js', OUTPUT_DIR, 'getElement', iconVNodes); +generateExportsFile('react.js', OUTPUT_DIR, 'getReactComponent', iconVNodes); +generateExportsFile('vue.js', OUTPUT_DIR, 'getVueComponent', iconVNodes); diff --git a/scripts/optimizeSvgs.js b/scripts/optimizeSvgs.js new file mode 100644 index 000000000..4ba16022c --- /dev/null +++ b/scripts/optimizeSvgs.js @@ -0,0 +1,16 @@ +import fs from 'fs'; +import path from 'path'; + +const OUT_DIR = path.resolve(__dirname, '../dist/icons'); + +console.log(`Optimizing SVGs in ${OUT_DIR}...`); + +const svgFiles = fs.readdirSync(IN_DIR).filter(file => path.extname(file) === '.svg'); +console.log(svgFiles); + + +// Object.keys(icons).forEach(name => { +// const svg = icons[name].toSvg(); + +// fs.writeFileSync(path.join(OUT_DIR, `${name}.svg`), svg); +// }); diff --git a/scripts/render/processSvg.js b/scripts/render/processSvg.js new file mode 100644 index 000000000..44d3ec6b4 --- /dev/null +++ b/scripts/render/processSvg.js @@ -0,0 +1,58 @@ +import Svgo from 'svgo'; +import cheerio from 'cheerio'; +import { format } from 'prettier'; + +import DEFAULT_ATTRS from '../src/default-attrs.json'; + +/** + * Process SVG string. + * @param {string} svg - An SVG string. + * @param {Promise} + */ +function processSvg(svg) { + return ( + optimize(svg) + .then(setAttrs) + .then(format) + // remove semicolon inserted by prettier + // because prettier thinks it's formatting JSX not HTML + .then(svg => svg.replace(/;/g, '')) + ); +} + +/** + * Optimize SVG with `svgo`. + * @param {string} svg - An SVG string. + * @returns {Promise} + */ +function optimize(svg) { + const svgo = new Svgo({ + plugins: [ + { convertShapeToPath: false }, + { mergePaths: false }, + { removeAttrs: { attrs: '(fill|stroke.*)' } }, + { removeTitle: true }, + ], + }); + + return new Promise(resolve => { + svgo.optimize(svg, ({ data }) => resolve(data)); + }); +} + +/** + * Set default attibutes on SVG. + * @param {string} svg - An SVG string. + * @returns {string} + */ +function setAttrs(svg) { + const $ = cheerio.load(svg); + + Object.keys(DEFAULT_ATTRS).forEach(key => + $('svg').attr(key, DEFAULT_ATTRS[key]), + ); + + return $('body').html(); +} + +export default processSvg; diff --git a/src/getElement.js b/src/getters/getElement.js similarity index 100% rename from src/getElement.js rename to src/getters/getElement.js diff --git a/src/getReactComponent.js b/src/getters/getReactComponent.js similarity index 100% rename from src/getReactComponent.js rename to src/getters/getReactComponent.js diff --git a/src/getVueComponent.js b/src/getters/getVueComponent.js similarity index 100% rename from src/getVueComponent.js rename to src/getters/getVueComponent.js diff --git a/src/icons/.gitkeep b/src/icons/.gitkeep deleted file mode 100644 index e69de29bb..000000000