From 849df84c5940f517168a96a1a843e2654244cc1e Mon Sep 17 00:00:00 2001 From: David Rodriguez Feito Date: Wed, 20 Jul 2022 00:16:28 -0300 Subject: [PATCH] fix: improve build to reduce bundle size --- .babelrc | 13 ---------- .gitignore | 1 + babel.config.js | 27 ++++++++++++++++++++ package.json | 18 +++++++++++--- scripts/build.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ yarn.lock | 2 +- 6 files changed, 107 insertions(+), 18 deletions(-) delete mode 100644 .babelrc create mode 100644 babel.config.js create mode 100644 scripts/build.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index ea4ccba96..000000000 --- a/.babelrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-react", - ["@babel/preset-typescript", { - "isTSX": true, - "allExtensions": true - }]], - "plugins": [ - "@babel/plugin-transform-runtime" - ] -} - diff --git a/.gitignore b/.gitignore index 305106ca3..4712d138e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ coverage .env package-lock.json components +esm propTypes libs styles diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 000000000..63d3ae814 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,27 @@ +module.exports = function getBabelConfig(api) { + const useESModules = api.env(['esm']); + + const presets = [ + [ + '@babel/preset-env', + { + modules: useESModules ? false : 'commonjs', + }, + ], + '@babel/preset-react', + [ + '@babel/preset-typescript', + { + isTSX: true, + allExtensions: true, + }, + ], + ]; + const plugins = ['@babel/plugin-transform-runtime']; + + return { + presets, + plugins, + comments: false, + }; +}; diff --git a/package.json b/package.json index 47c605d05..5cb7e6b1e 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "scripts": { "start": "./node_modules/.bin/styleguidist server", "build:library": "./node_modules/.bin/styleguidist build", - "build:components": "npx babel ./src --out-dir ./", + "build:components": "yarn build:components:node && yarn build:components:esm", + "build:components:node": "node ./scripts/build node --out-dir ./", + "build:components:esm": "node ./scripts/build esm --out-dir ./", "build:copy-ts-files": "node ./scripts/copy-files.js", "build": "npm-run-all --parallel build:components --serial build:copy-ts-files", "prepublishOnly": "yarn clean && yarn build", @@ -52,10 +54,17 @@ "react-dom": ">=16.8.0", "styled-components": ">=4.3.2 <6" }, - "main": "index.js", - "types": "index.d.ts", + "main": "./index.js", + "module": "./esm/index.js", + "exports": { + "import": "./esm/index.js", + "require": "./index.js" + }, + "types": "./index.d.ts", + "sideEffects": false, "files": [ "components", + "esm", "styles", "libs", "index.d.ts" @@ -192,7 +201,8 @@ "stylelint-scss": "^3.3.0", "wait-on": "^6.0.1", "webdriverio": "^7", - "webpack": "^4.41.2" + "webpack": "^4.41.2", + "yargs": "^17.5.1" }, "pre-push": [ "lint", diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 000000000..6a8851c5c --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,64 @@ +const childProcess = require('child_process'); +const path = require('path'); +const yargs = require('yargs'); +const { promisify } = require('util'); + +const exec = promisify(childProcess.exec); + +const validBundles = [ + // modern build with a rolling target using ES6 modules + 'esm', + // build for node using commonJS modules + 'node', +]; + +async function run(argv) { + const { bundle, outDir: relativeOutDir } = argv; + const env = { + NODE_ENV: 'production', + BABEL_ENV: bundle, + }; + const babelConfigPath = path.resolve(__dirname, '../babel.config.js'); + const srcDir = path.resolve('./src'); + const outDir = path.resolve( + relativeOutDir, + // We generally support top level path imports e.g. + // 1. `import ArrowDownIcon from '@mui/icons-material/ArrowDown'`. + // 2. `import Typography from '@mui/material/Typography'`. + // The first case resolves to a file while the second case resolves to a package first i.e. a package.json + // This means that only in the second case the bundler can decide whether it uses ES modules or CommonJS modules. + // Different extensions are not viable yet since they require additional bundler config for users and additional transpilation steps in our repo. + // Switch to `exports` field in v6. + { + node: './', + esm: './esm', + }[bundle], + ); + const babelArgs = ['--config-file', babelConfigPath, srcDir, '--out-dir', outDir]; + const command = ['yarn babel', ...babelArgs].join(' '); + const { stderr, stdout } = await exec(command, { env: { ...process.env, ...env } }); + + if (stderr) { + throw new Error(`'${command}' failed with \n${stderr}`); + } + console.log(stdout); +} + +yargs + .command({ + command: '$0 ', + description: 'build package', + builder: command => { + return command + .positional('bundle', { + description: `Valid bundles: "${validBundles.join('" | "')}"`, + type: 'string', + }) + .option('out-dir', { default: './', type: 'string' }); + }, + handler: run, + }) + .help() + .strict(true) + .version(false) + .parse(); diff --git a/yarn.lock b/yarn.lock index e7d7e5483..31cea8222 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17992,7 +17992,7 @@ yargs@^13.3.0, yargs@^13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^17.0.0: +yargs@^17.0.0, yargs@^17.5.1: version "17.5.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==