Skip to content

rolldown 2019 #8

Description

@tunnckoCore
const fs = require('fs');
const path = require('path');
const rollup = require('rollup');
const argParser = require('mri');
const commonjs = require('rollup-plugin-commonjs');
const progress = require('rollup-plugin-progress');
const filesize = require('rollup-plugin-filesize');
const resolve = require('rollup-plugin-node-resolve');
const terser = require('rollup-plugin-terser');
const babel = require('rollup-plugin-babel');
const json = require('rollup-plugin-json');
const builtinModules = require('builtin-modules');

function prettierPlugin() {
  return {
    name: 'rollup-plugin-prettier-bundle',
    generateBundle(output) {},
  };
}

async function createConfig(input, options) {
  const opts = Object.assign({}, options);
  const extMap = {
    es: '.mjs',
    cjs: '.js',
  };
  const destMap = {
    es: 'module',
    cjs: 'main',
  };

  const cwd = process.cwd();
  const outDir = (x) => opts.outDir || path.join(cwd, 'dist', destMap[x]);
  const outFile = (x) => path.join(outDir(x), `index${extMap[x]}`);

  const join = (...x) => path.join(cwd, ...x);

  const pkg = require(join('package.json'));

  const exts = arrayify(opts.extensions);
  const extensions =
    exts.length > 0 ? exts : ['.js', '.jsx', '.mjs', '.ts', '.tsx'];

  const possibleInputs = [
    input,
    join('index.js'),
    join('src', 'index.js'),
    join('src', 'index.mjs'),
    join('src', 'index.ts'),
  ];

  // first existing, for now
  const [inputFile] = possibleInputs.filter((x) => fs.existsSync(x));
  const license = `/** Released under the ${opts.license ||
    pkg.license} License. See LICENSE file. */`;

  const outMap = {
    cjs: {
      exports: 'named',
      banner: license,
      file: outFile('cjs'),
      format: 'cjs',
      preferConst: true,

      // don't break oldschool/classic/normal node.js
      outro: 'module.exports = exports.default || exports;',
    },
    es: {
      exports: 'named',
      banner: license,
      file: outFile('es'),
      format: 'es',
      preferConst: true,
    },
  };
  outMap.esm = outMap.es;

  let formats = arrayify(opts.format)
    .reduce((acc, x) => acc.concat(x.indexOf(',') > -1 ? x.split(',') : x), [])
    .filter(Boolean);

  let output = null;

  if (formats.length === 0) {
    formats = ['cjs', 'es'];
  }
  if (formats.length === 1) {
    output = outMap[formats[0]];
  } else {
    output = formats.map((x) => outMap[x]);
  }

  return {
    input: inputFile,
    output,

    external: builtinModules,

    inlineDynamicImports: true,
    experimentalTopLevelAwait: true,

    plugins: [
      progress(),
      resolve({
        preferBuiltins: true,
        module: true,
        jsnext: true,
        main: true,
      }),
      json({ preferConst: true }),
      babel({
        exclude: 'node_modules/**',
        externalHelpers: true,
        extensions,
      }),
      commonjs({
        extensions,
      }),
      opts.minify && terser.terser(),
      filesize({
        showBrotliSize: true,
        showGzippedSize: true,
        showMinifiedSize: true,
      }),
    ],
  };
}

const argv = argParser(process.argv.slice(2), {
  alias: {
    i: 'input',
    d: ['out-dir', 'outdir', 'outDir'],
    f: 'format',
    m: 'minify',
    x: ['ext', 'extensions'],
    l: ['license'],
  },
});

let ROLLUP_CACHE = null;

createConfig(argv.input || argv._[0], argv)
  .then(async (cfg) => {
    const bundle = await rollup.rollup(
      Object.assign({}, cfg, { cache: ROLLUP_CACHE }),
    );

    ROLLUP_CACHE = bundle.cache;

    arrayify(cfg.output).map(async (outputOptions) => {
      await bundle.write(outputOptions);
    });
  })
  .catch(console.error);

function arrayify(val) {
  if (!val) return [];
  if (Array.isArray(val)) return val;
  return [val];
}

run with

node rolldown.js [src/index.js]

by defaults tries index.js, src/index.js, src/index.mjs and src/index.ts, works with TypeScript out of the box and generates CJS and ESM bundles with bundled deps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions