const path = require('path'); const babel = require('rollup-plugin-babel'); const commonjs = require('@rollup/plugin-commonjs'); const json = require('@rollup/plugin-json'); const nodeResolve = require('@rollup/plugin-node-resolve'); const replace = require('@rollup/plugin-replace'); const { terser } = require('rollup-plugin-terser'); const localeStringValidator = require('./tools/locale-string-validator'); const cwd = process.cwd(); const pkg = require(path.join(cwd, 'package.json')); // eslint-disable-line const { name, version, license } = pkg; const targetName = name.split('/')[1]; const targetDirName = 'dist'; const targetDir = path.join(cwd, targetDirName); const getFileName = (format, dev) => `${targetName}${format ? `.${format}` : ''}${dev ? '.dev' : ''}.js`; const getTargetFileName = (format, dev) => `${targetDirName}/${getFileName(format, dev)}`; // verify package targets and names if (pkg.main !== 'index.js') { throw Error(`main target must be index.js`); } // in our webpack/rollup configs we include '.dev.js' as file extension when building // a dev distribution, the module target should therefore end with '.esm' and not with '.esm.js' // so that the node resolve algorithm finds the correct module based on module format and dev mode // e.g. '@nebula.js/supernova' -> '@nebula.js/supernova/dist/supernova.esm.dev.js' const moduleTargetName = getTargetFileName('esm').replace(/\.js$/, ''); if (pkg.module && pkg.module !== moduleTargetName) { throw Error(`module target must be ${moduleTargetName}`); } if (pkg.unpkg && pkg.unpkg !== getTargetFileName('')) { throw Error(`unpkg target must be ${getTargetFileName('')}`); } if (pkg.jsdelivr && pkg.jsdelivr !== getTargetFileName('')) { throw Error(`jsdelivr target must be ${getTargetFileName('')}`); } const banner = `/* * ${name} v${version} * Copyright (c) ${new Date().getFullYear()} QlikTech International AB * Released under the ${license} license. */ `; const browserList = [ 'last 2 Chrome versions', 'last 2 Firefox versions', 'last 2 Edge versions', 'Safari >= 10.0', 'iOS >= 11.2', ]; const GLOBALS = { react: 'React', 'react-dom': 'ReactDOM', '@nebula.js/supernova': 'supernova', }; const propTypes = [ 'array', 'bool', 'func', 'number', 'object', 'string', 'symbol', 'any', 'arrayOf', 'element', 'instanceOf', 'node', 'objectOf', 'oneOf', 'oneOfType', 'shape', 'exact', 'elementType', ]; const watch = process.argv.indexOf('-w') > 2; const config = (isEsm, dev = false) => { const umdName = targetName .replace(/-([a-z])/g, (m, p1) => p1.toUpperCase()) .split('.js') .join(''); if (Object.keys(pkg.dependencies || {}).length) { throw new Error('Dependencies for a web javascript library makes no sense'); } const peers = Object.keys(pkg.peerDependencies || {}); // all peers should be externals for esm bundle const esmExternals = peers; // peers that are not devDeps should be externals for full bundle const bundleExternals = peers.filter(p => typeof (pkg.devDependencies || {})[p] === 'undefined'); const external = isEsm ? esmExternals : bundleExternals; const globals = {}; external.forEach(e => { if ([GLOBALS[e]]) { globals[e] = GLOBALS[e]; } }); const cfg = { input: path.resolve(cwd, 'src', 'index'), output: { file: path.resolve(targetDir, getFileName(isEsm ? 'esm' : '', dev)), format: isEsm ? 'esm' : 'umd', exports: ['supernova', 'test-utils'].indexOf(targetName) !== -1 ? 'named' : 'default', name: umdName, sourcemap: false, banner, globals, }, external, plugins: [ replace({ __NEBULA_DEV__: dev, 'process.env.NODE_ENV': JSON.stringify(isEsm ? 'development' : 'production'), 'process.env.NEBULA_VERSION': JSON.stringify(version), }), nodeResolve({ extensions: [dev ? '.dev.js' : false, '.js', '.jsx'].filter(Boolean), }), json(), commonjs({ namedExports: { react: [ 'useState', 'useEffect', 'useLayoutEffect', 'useRef', 'useReducer', 'useImperativeHandle', 'forwardRef', 'useContext', 'useCallback', 'useMemo', 'createElement', 'PureComponent', 'isValidElement', 'Children', 'cloneElement', ], 'react-dom': ['createPortal', 'findDOMNode'], 'react-is': ['ForwardRef', 'isFragment'], 'react-transition-group/node_modules/prop-types/index.js': propTypes, 'prop-types/index.js': propTypes, '@material-ui/utils/node_modules/prop-types': propTypes, }, }), babel({ babelrc: false, include: [ '/**/apis/locale/**', '/**/apis/nucleus/**', '/**/apis/snapshooter/**', '/**/apis/supernova/**', '/**/apis/theme/**', '/**/packages/ui/**', ], presets: [ [ '@babel/preset-env', { modules: false, targets: { browsers: [...browserList, ...['ie 11', 'chrome 47']], }, }, ], ], plugins: [['@babel/plugin-transform-react-jsx'], [localeStringValidator, {}]], }), ], }; if (!dev) { cfg.plugins.push( terser({ output: { preamble: banner, }, }) ); } return cfg; }; let dist = [ // production watch ? false : config(), // dev watch ? false : config(false, true), // esm pkg.module ? config(true) : false, // esm dev pkg.module ? config(true, true) : false, ]; if (targetName === 'test-utils') { dist = [config(false)]; } module.exports = dist.filter(Boolean);