/* eslint-disable no-console */ const path = require('path'); const crypto = require('crypto'); 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.cjs'); const cwd = process.cwd(); const pkg = require(path.join(cwd, 'package.json')); // eslint-disable-line const { name, version, license } = pkg; let corePkg; try { corePkg = require(path.join(cwd, 'core', 'package.json')); // eslint-disable-line } catch (e) { // do nothing } const versionHash = crypto.createHash('md5').update(version).digest('hex').slice(0, 4); 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/stardust' -> '@nebula.js/stardust/dist/stardust.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 >= 11.0', 'iOS >= 12.2', ]; const GLOBALS = { react: 'React', 'react-dom': 'ReactDOM', '@nebula.js/stardust': 'stardust', }; const watch = process.argv.indexOf('-w') > 2; const TYPES_SCOPE_RX = /^@qlik\/api/; const config = ({ format = 'umd', debug = false, file, targetPkg }) => { const umdName = targetName .replace(/-([a-z])/g, (m, p1) => p1.toUpperCase()) .split('.js') .join(''); if (Object.keys(targetPkg.dependencies || {}).filter((dep) => !TYPES_SCOPE_RX.test(dep)).length) { console.log(targetPkg.name); console.log(JSON.stringify(Object.keys(targetPkg.dependencies || {}).filter((dep) => !TYPES_SCOPE_RX.test(dep)))); throw new Error('Dependencies for a web javascript library makes no sense'); } const peers = Object.keys(targetPkg.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 useDirectoryOutput = format === 'systemjs'; const external = peers; const globals = {}; external.forEach((e) => { if ([GLOBALS[e]]) { globals[e] = GLOBALS[e]; } else { console.warn(`External '${e}' has no global value`); } }); const cfg = { onwarn(warning, warn) { // Supress "use client" warnings coming from MUI bundling if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes(`"use client"`)) { return; } if (warning.code === 'INVALID_ANNOTATION' && warning.frame.includes(`// eslint-disable-next-line react`)) { return; } if (warning.code === 'INVALID_ANNOTATION' && warning.message.includes(`@mui/material`)) { return; } if (warning.code === 'CIRCULAR_DEPENDENCY' && warning.message.includes(`node_modules/semver`)) { return; } warn(warning); }, input: path.resolve(cwd, 'src', 'index'), output: useDirectoryOutput ? { dir: path.dirname(file), entryFileNames: path.basename(file), chunkFileNames: 'chunks/[name]-[hash].js', format, exports: ['test-utils', 'stardust'].indexOf(targetName) !== -1 ? 'named' : 'default', sourcemap: true, banner, globals, inlineDynamicImports: false, } : { file, format, exports: ['test-utils', 'stardust'].indexOf(targetName) !== -1 ? 'named' : 'default', name: umdName, sourcemap: true, banner, globals, inlineDynamicImports: true, }, external, plugins: [ replace({ __NEBULA_DEV__: debug, 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV === 'development' ? 'development' : 'production'), 'process.env.NEBULA_VERSION': JSON.stringify(version), 'process.env.NEBULA_VERSION_HASH': JSON.stringify(versionHash), preventAssignment: true, }), nodeResolve({ extensions: [debug ? '.dev.js' : false, '.js', '.jsx'].filter(Boolean), browser: true, }), json(), commonjs(), babel({ babelHelpers: 'bundled', babelrc: false, include: [ /\/apis\/conversion\//, /\/apis\/enigma-mocker\//, /\/apis\/locale\//, /\/apis\/nucleus\//, /\/apis\/snapshooter\//, /\/apis\/stardust\//, /\/apis\/supernova\//, /\/apis\/theme\//, /\/packages\/ui\//, ], presets: [ [ '@babel/preset-env', { modules: false, targets: { browsers: [...browserList, 'chrome 62'], }, }, ], ], plugins: [['@babel/plugin-transform-react-jsx'], [localeStringValidator, {}]], }), ], }; if (!debug) { cfg.plugins.push( terser({ output: { preamble: banner, }, }) ); } return cfg; }; let dist = [ // production watch ? false : config({ targetPkg: pkg, file: path.resolve(targetDir, getFileName()), }), // dev watch ? false : config({ debug: true, targetPkg: pkg, file: path.resolve(targetDir, getFileName('', true)), }), // esm pkg.module ? config({ format: 'esm', targetPkg: pkg, file: path.resolve(targetDir, getFileName('esm', false)), }) : false, // esm dev pkg.module ? config({ debug: true, format: 'esm', targetPkg: pkg, file: path.resolve(targetDir, getFileName('esm', true)), }) : false, targetName === 'stardust' ? config({ format: 'systemjs', targetPkg: pkg, file: path.resolve(targetDir, getFileName('systemjs', false)), }) : false, targetName === 'stardust' ? config({ debug: true, format: 'systemjs', targetPkg: pkg, file: path.resolve(targetDir, getFileName('systemjs', true)), }) : false, // core esm corePkg && corePkg.module ? config({ format: 'esm', targetPkg: corePkg, file: path.resolve(cwd, 'core', corePkg.module), }) : false, // core esm dev corePkg && corePkg.module ? config({ debug: true, format: 'esm', targetPkg: corePkg, file: path.resolve(cwd, 'core', 'esm', 'dev.js'), }) : false, ]; if (targetName === 'test-utils') { dist = [ config({ targetPkg: pkg, file: path.resolve(targetDir, getFileName()), }), ]; } module.exports = dist.filter(Boolean);