Last active
May 29, 2024 17:28
-
-
Save rxnlabs/3386bcce53c77064c64411e55d02e46f to your computer and use it in GitHub Desktop.
Custom RollupJS configuration file to support multiple entry points using a Glob import and also excluding entries using a Glob import. Outputs all of the entries to a custom directory and supports exporting as an IIFE (unlike https://github.com/alfredosalzillo/rollup-plugin-multi-input and https://www.npmjs.com/package/@rollup/plugin-multi-entry)…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "custom-rollup-js-config-multi-entry-glob", | |
"version": "0.1.0", | |
"description": "package.json for custom RollupJS configuration that supports glob'ing entries from a directory or multiple directories", | |
"author": "rxnlabs", | |
"license": "GPL-2.0-or-later", | |
"scripts": { | |
"dev": "npm run scripts -- --watch", | |
"build": "npm run scripts", | |
"scripts": "rollup --config" | |
}, | |
"devDependencies": { | |
"@rollup/plugin-commonjs": "^25.0.7", | |
"@rollup/plugin-node-resolve": "^15.2.3", | |
"@rollup/plugin-swc": "^0.3.0", | |
"@rollup/plugin-terser": "^0.4.4", | |
"fast-glob": "^3.3.2", | |
"rollup": "^4.17.2", | |
"rollup-plugin-wp-resolve": "^1.0.9", | |
}, | |
"dependencies": {} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// rollup.config.mjs (rollup.config.js file writtin in ES6 using the .mjs file extension so it's treated like a ES6 module) | |
/** | |
* @file | |
* This script is a custom configuration file for RollupJS. This config's main feature is the ability | |
* to import multiple entries by leveraging Glob patterns and regex file matching, essentially | |
* enlarging the base functionality of RollupJS. Also, it supports | |
* excluding certain entries from being bundled using similar Glob patterns. | |
* | |
* Furthermore, this configuration is designed in a way to output | |
* multiple bundled files into a specific directory. Each output file's | |
* name is the same name as it's input ('entry') file, hence maintaining | |
* a direct correlation between source and bundled files. It also generates a minified version | |
* of the entry as a separate file with the .min.js as the file extension. | |
* | |
* RollupJS doesn't natively provide this capability but this should work with almost any current rollupjs configuration | |
* while also being able to output code in iife format, so it can execute in browsers. | |
* - RollupJS plugin https://www.npmjs.com/package/@rollup/plugin-multi-entry does not do this since it bundles all entries into a single file instead of each entry also outputting into a distinct file | |
* - RollupJS plugin https://github.com/alfredosalzillo/rollup-plugin-multi-input does this but only for esm moduels and umd modules. Iife is not supported. | |
* - Preservermodules https://rollupjs.org/configuration-options/#output-preservemodules does not do this | |
* - Preservermodulesroot https://rollupjs.org/configuration-options/#output-preservemodulesroot does not do this | |
*/ | |
// rollup config.js | |
import {rollup} from "rollup"; | |
// when importing node_modules package into custom code created by us, RollupJS will look for that import in the node_modules folder if a full file path is not given when the module is imported | |
import resolve from '@rollup/plugin-node-resolve'; | |
// convert CommonJS modules to es6, so they can be added to the bundle | |
import commonjs from '@rollup/plugin-commonjs'; | |
// used to convert .jsx files and code to js and replaces the use of babel to transpile es6 code to older browsers (used when building custom blocks or extending the block editor using React components) | |
import swc from '@rollup/plugin-swc'; | |
// used to for file minification | |
import terser from '@rollup/plugin-terser'; | |
// resolve wordpress external dependencies, similar to the dependy-extraction-webpack-plugin https://github.com/WordPress/gutenberg/tree/trunk/packages/dependency-extraction-webpack-plugin | |
import wpResolve from 'rollup-plugin-wp-resolve'; | |
// used to import multiple entry files to this custom Rollup config using a glob pattern | |
import fg from 'fast-glob'; | |
import path from 'node:path'; | |
/** | |
* Transform the entry file so that the output file is named the same file name as the entry file but remove the original root folder from the final file output directory. | |
*/ | |
const createEntryOutput = (entryFiles, removeRelativePath, outputDir, createMinificationFiles) => { | |
return entryFiles.map((relativeFilePath) => { | |
let outputFile = relativeFilePath; | |
// remove the relative file folder path from the beginning of the file in case we don't want the exact file structure | |
if (typeof removeRelativePath === 'string' && outputFile.startsWith(removeRelativePath)) { | |
outputFile = outputFile.split(removeRelativePath)[1]; | |
} | |
// output the file into a new output directory | |
outputFile = ltrim(outputFile, '/'); | |
if (typeof outputDir === 'string' && outputDir.length) { | |
outputFile = `${ltrim(outputDir, '/')}/${outputFile}`; | |
} | |
// create an entry output object with the name of the entry file appended with the text .min to specify that this is a minimized file | |
const fileExtension = path.extname(relativeFilePath); | |
const bundleFileWithoutExtension = outputFile.slice(0, outputFile.length - fileExtension.length); | |
// use the file output path as the name of the exported variable in the iife in case the output file exports a value | |
// see https://rollupjs.org/configuration-options/#output-name | |
const iifeVarName = bundleFileWithoutExtension.replace(/[\/\.]/g, '_').toUpperCase(); | |
let minifiedOutputFile = ''; | |
if (createMinificationFiles && bundleFileWithoutExtension.length) { | |
minifiedOutputFile = `${bundleFileWithoutExtension}.min${fileExtension}`; | |
} | |
return { | |
entry: relativeFilePath, | |
output: outputFile, | |
min_output: minifiedOutputFile, | |
name: iifeVarName | |
}; | |
}); | |
}; | |
/** | |
* Custom, lightweight JS version of PHP's ltrim function | |
*/ | |
const ltrim = (str, charToRemove) => { | |
while (str.startsWith(charToRemove)) { | |
str = str.slice(charToRemove.length); | |
} | |
return str; | |
} | |
// specify these imports/requires as global modules so RollupJS will not try to compile their code into the bundle. | |
// specify the name of the global variable that the import will be transformed into when the file is bundled, which will also refer to the name of the variable in the global scope | |
const globalsTransform = { | |
jquery: '$', | |
react: 'window.React', | |
'react-dom': 'window.ReactDOM', | |
wp: 'window.wp', | |
}; | |
// increase the time in milliseconds for a build delay to give the filesystem a chance for the file content to be fully written to disk. | |
// Decreases chances RollupJS will output an empty file | |
// see https://rollupjs.org/configuration-options/#watch-builddelay | |
const buildDelay = 500; | |
// get the list of entry files using a glob and exclude files using a glob. Exclude files in the partials folder and in the vendor folder | |
const entryFiles = fg.sync(['src/js/**/*.js', '!src/js/**/edit.js', '!src/js/partials/**/*.js', '!src/js/vendor/**/*.js']); | |
// create minification version of the entries | |
let createMinificationFiles = false; | |
const entryOutputFiles = createEntryOutput(entryFiles, 'src/', 'build', createMinificationFiles); | |
// add multiple files to to the rollup config so multiple bundles are built as individual files | |
let rollupConfig = entryOutputFiles.map((entryOutputFile) => { | |
let outputConfig = [ | |
{ | |
file: entryOutputFile.output, | |
format: 'iife', | |
name: entryOutputFile.name, | |
globals: globalsTransform, | |
sourcemap: true, | |
} | |
]; | |
if (entryOutputFile.min_output.length) { | |
// do a deep clone of the config object so we can add the terser() plugin to the minify config | |
let minifyConfig = structuredClone( outputConfig[0] ); | |
minifyConfig.file = entryOutputFile.min_output; | |
minifyConfig.plugins = minifyConfig.plugins || []; | |
minifyConfig.plugins.push(terser()); | |
outputConfig.push(minifyConfig); | |
} | |
return { | |
input: entryOutputFile.entry, | |
output: outputConfig, | |
external: [Object.keys(globalsTransform)], | |
plugins: [ | |
wpResolve(), | |
resolve({ extensions: ['.js', '.ts', '.jsx'] }), | |
swc({ swc: {'jsc': { 'parser': {'syntax': 'ecmascript', 'jsx': true}}, 'minify': false }, exclude: ['node_modules/**'] }), | |
commonjs() | |
], | |
watch: { | |
clearScreen: false, | |
exclude: 'node_modules/**', | |
include: 'src/js/**/*.js', | |
buildDelay: buildDelay, | |
} | |
}; | |
}); | |
// add any additional configs to the rollup export | |
const additionalConfigs = [ | |
/*{ | |
input: '', | |
output: {}, | |
plugins: [], | |
watch: { | |
clearScreen: false, | |
exclude: 'node_modules/**' | |
}, | |
}*/ | |
]; | |
rollupConfig = rollupConfig.concat(additionalConfigs).flat(); | |
export default rollupConfig; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment