diff --git a/.changeset/clean-years-drop.md b/.changeset/clean-years-drop.md new file mode 100644 index 000000000..206484f64 --- /dev/null +++ b/.changeset/clean-years-drop.md @@ -0,0 +1,5 @@ +--- +"@onflow/fcl": patch +--- + +Minify UMD build diff --git a/.changeset/swift-chairs-rhyme.md b/.changeset/swift-chairs-rhyme.md new file mode 100644 index 000000000..24b586b57 --- /dev/null +++ b/.changeset/swift-chairs-rhyme.md @@ -0,0 +1,5 @@ +--- +"@onflow/fcl-bundle": minor +--- + +Automatically compress bundle if entry file ends in .min.js diff --git a/package-lock.json b/package-lock.json index b2c20b382..d568c5c3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2477,6 +2477,15 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.13", "license": "MIT" @@ -5901,7 +5910,6 @@ }, "node_modules/acorn": { "version": "8.7.0", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -6802,7 +6810,6 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "dev": true, "license": "MIT" }, "node_modules/buffer-xor": { @@ -7383,7 +7390,6 @@ }, "node_modules/commander": { "version": "2.20.3", - "dev": true, "license": "MIT" }, "node_modules/common-ancestor-path": { @@ -9717,7 +9723,6 @@ }, "node_modules/has-flag": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11739,7 +11744,6 @@ }, "node_modules/jest-worker": { "version": "26.6.2", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -12835,7 +12839,6 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -15067,7 +15070,6 @@ }, "node_modules/randombytes": { "version": "2.1.0", - "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" @@ -15902,6 +15904,37 @@ "decode-uri-component": "^0.2.0" } }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/rsvp": { "version": "4.8.5", "dev": true, @@ -16303,7 +16336,6 @@ }, "node_modules/serialize-javascript": { "version": "4.0.0", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" @@ -16701,7 +16733,6 @@ }, "node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -16721,7 +16752,6 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -17231,7 +17261,6 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -20650,7 +20679,8 @@ "commander": "^9.3.0", "lodash": "^4.17.21", "rollup": "^2.75.5", - "rollup-plugin-sourcemaps": "^0.6.3" + "rollup-plugin-sourcemaps": "^0.6.3", + "rollup-plugin-terser": "^7.0.2" }, "bin": { "fcl-bundle": "src/cli.js" @@ -32595,6 +32625,15 @@ "@jridgewell/set-array": { "version": "1.1.1" }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.13" }, @@ -36565,7 +36604,8 @@ "commander": "^9.3.0", "lodash": "^4.17.21", "rollup": "^2.75.5", - "rollup-plugin-sourcemaps": "^0.6.3" + "rollup-plugin-sourcemaps": "^0.6.3", + "rollup-plugin-terser": "^7.0.2" }, "dependencies": { "@rollup/plugin-commonjs": { @@ -43659,8 +43699,7 @@ "dev": true }, "acorn": { - "version": "8.7.0", - "dev": true + "version": "8.7.0" }, "acorn-globals": { "version": "6.0.0", @@ -44276,8 +44315,7 @@ } }, "buffer-from": { - "version": "1.1.2", - "dev": true + "version": "1.1.2" }, "buffer-xor": { "version": "1.0.3", @@ -44676,8 +44714,7 @@ } }, "commander": { - "version": "2.20.3", - "dev": true + "version": "2.20.3" }, "common-ancestor-path": { "version": "1.0.1", @@ -46392,8 +46429,7 @@ } }, "has-flag": { - "version": "4.0.0", - "dev": true + "version": "4.0.0" }, "has-symbols": { "version": "1.0.2" @@ -47806,7 +47842,6 @@ }, "jest-worker": { "version": "26.6.2", - "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -48615,8 +48650,7 @@ } }, "merge-stream": { - "version": "2.0.0", - "dev": true + "version": "2.0.0" }, "merge2": { "version": "1.4.1", @@ -50217,7 +50251,6 @@ }, "randombytes": { "version": "2.1.0", - "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -50806,6 +50839,30 @@ } } }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "dependencies": { + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + } + } + }, "rsvp": { "version": "4.8.5", "dev": true @@ -51077,7 +51134,6 @@ }, "serialize-javascript": { "version": "4.0.0", - "dev": true, "requires": { "randombytes": "^2.1.0" } @@ -51359,8 +51415,7 @@ "dev": true }, "source-map": { - "version": "0.6.1", - "dev": true + "version": "0.6.1" }, "source-map-resolve": { "version": "0.5.3", @@ -51375,7 +51430,6 @@ }, "source-map-support": { "version": "0.5.21", - "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -51748,7 +51802,6 @@ }, "supports-color": { "version": "7.2.0", - "dev": true, "requires": { "has-flag": "^4.0.0" } diff --git a/packages/fcl-bundle/README.md b/packages/fcl-bundle/README.md index 76782a935..3c5764de9 100644 --- a/packages/fcl-bundle/README.md +++ b/packages/fcl-bundle/README.md @@ -20,6 +20,8 @@ All of the configuration for FCL-Bundle currently takes place within the `packag | `module` | No | string | Specify esm bundle output path if not manually specified by [Output Configuration](#output-configuration) (as well as esm entry point if not overriden by `package.exports`) | | `unpkg` | No | string | Specify umd bundle output path if not manually specified by [Output Configuration](#output-configuration) (as well as umd entry point if not overriden by `package.exports`) | +> **Note:** If output paths end in ".min.js", the resulting bundle will be minified + ### Output Configuration @@ -35,6 +37,8 @@ An empty Output Configuration will fallback to the [default outputs](#default-ou In practice, these Output Configuration objects will be consumed as shown in the [Source Configuration](#source-configuration) below. +> **Note:** If output paths end in ".min.js", the resulting bundle will be minified + ### Source Configuration A source configuration can be provided in one of three ways: diff --git a/packages/fcl-bundle/package.json b/packages/fcl-bundle/package.json index 50ad47b0d..44e3851e9 100644 --- a/packages/fcl-bundle/package.json +++ b/packages/fcl-bundle/package.json @@ -23,7 +23,8 @@ "commander": "^9.3.0", "lodash": "^4.17.21", "rollup": "^2.75.5", - "rollup-plugin-sourcemaps": "^0.6.3" + "rollup-plugin-sourcemaps": "^0.6.3", + "rollup-plugin-terser": "^7.0.2" }, "bin": { "fcl-bundle": "src/cli.js" diff --git a/packages/fcl-bundle/src/build/build-watch.js b/packages/fcl-bundle/src/build/build-watch.js index e899fee6b..483da7d91 100644 --- a/packages/fcl-bundle/src/build/build-watch.js +++ b/packages/fcl-bundle/src/build/build-watch.js @@ -1,15 +1,15 @@ -const WatcherFactory = require("./watcher-factory") +const WatcherPool = require("./watcher-pool") +const {watch} = require("rollup") const getInputOptions = require("./get-input-options") const getOutputOptions = require("./get-output-options") module.exports = async function buildModulesWatch(builds, package) { - const watcherFactory = new WatcherFactory(builds.length) - watcherFactory.eventEmitter.on("event", handleWatcherEvent) - - await Promise.all( - builds.map(build => buildModuleWatch(build, package, watcherFactory)) + const watcherOptionsList = builds.map(build => + getWatcherOptions(build, package) ) + const watcherPool = new WatcherPool(watcherOptionsList) + watcherPool.on("event", handleWatcherEvent) function handleWatcherEvent(event) { switch (event.code) { @@ -27,24 +27,13 @@ module.exports = async function buildModulesWatch(builds, package) { } } -async function buildModuleWatch(build, package, watcherFactory) { +function getWatcherOptions(build, package) { const inputOptions = getInputOptions(package, build) const outputOptions = getOutputOptions(package, build) - const watchOptions = { + const watcherOptions = { ...inputOptions, output: [outputOptions], } - let watcher, buildError - try { - watcher = watcherFactory.makeWatcher(watchOptions) - } catch (error) { - buildError = error - } - - if (watcher) watcher.close() - - if (buildError) { - throw new Error(buildError) - } + return watcherOptions } diff --git a/packages/fcl-bundle/src/build/get-input-options.js b/packages/fcl-bundle/src/build/get-input-options.js index bbece4c0f..49a5ff340 100644 --- a/packages/fcl-bundle/src/build/get-input-options.js +++ b/packages/fcl-bundle/src/build/get-input-options.js @@ -5,6 +5,7 @@ const replace = require("@rollup/plugin-replace") const sourcemap = require("rollup-plugin-sourcemaps") const {nodeResolve} = require("@rollup/plugin-node-resolve") const {babel} = require("@rollup/plugin-babel") +const {terser} = require("rollup-plugin-terser") const builtinModules = require("builtin-modules") @@ -72,6 +73,11 @@ module.exports = function getInputOptions(package, build) { ], sourceMaps: true, }), + /\.min\.js$/.test(build.entry) && + terser({ + ecma: 5, + toplevel: build.type == "cjs" || build.type == "esm", + }), sourcemap(), ], } diff --git a/packages/fcl-bundle/src/build/get-output-options.js b/packages/fcl-bundle/src/build/get-output-options.js index 8eb342b96..bfaaaf164 100644 --- a/packages/fcl-bundle/src/build/get-output-options.js +++ b/packages/fcl-bundle/src/build/get-output-options.js @@ -18,16 +18,15 @@ module.exports = function getOutputOptions(package, build) { inlineDynamicImports: true, sourcemap: true, plugins: [ - build.banner - ? banner( - isObject(build.banner) - ? build.banner - : { - banner: build.banner, - raw: true, - } - ) - : null, + build.banner && + banner( + isObject(build.banner) + ? build.banner + : { + banner: build.banner, + raw: true, + } + ), ], } diff --git a/packages/fcl-bundle/src/build/watcher-factory.js b/packages/fcl-bundle/src/build/watcher-factory.js deleted file mode 100644 index 2a79efd0a..000000000 --- a/packages/fcl-bundle/src/build/watcher-factory.js +++ /dev/null @@ -1,53 +0,0 @@ -const {watch} = require("rollup") -const {EventEmitter} = require("events") - -module.exports = function WatcherFactory(numWatchers) { - this.watchers = [] - this.eventEmitter = new EventEmitter() - this.eventBuffers = {} - this.numWatchers = numWatchers - - this.makeWatcher = watchOptions => { - const watcher = watch(watchOptions) - this.watchers.push(watcher) - - watcher.on("event", event => { - const {code} = event - - switch (code) { - case "ERROR": - console.error("Build failed!", event.error) - break - } - - if (!this.eventBuffers[code]) this.eventBuffers[code] = new EventBuffer() - this.eventBuffers[code].put(watcher, event) - - if (this.eventBuffers[code].size >= numWatchers) { - this.eventEmitter.emit("event", { - code, - events: this.eventBuffers[code], - }) - this.eventBuffers[code].clear() - } - }) - - return watcher - } -} - -function EventBuffer() { - this.events = [] - this.get = watcher => this.events.find(evt => evt.watcher === watcher)?.event - this.put = (watcher, event) => - this.events.push({ - watcher, - event, - }) - this.clear = () => (this.events = []) - Object.defineProperty(this, "size", { - get() { - return this.events.length - }, - }) -} diff --git a/packages/fcl-bundle/src/build/watcher-pool.js b/packages/fcl-bundle/src/build/watcher-pool.js new file mode 100644 index 000000000..f4f37b69b --- /dev/null +++ b/packages/fcl-bundle/src/build/watcher-pool.js @@ -0,0 +1,68 @@ +const {watch} = require("rollup") +const {EventEmitter} = require("events") + +class WatcherPool extends EventEmitter { + constructor(watcherOptionsList) { + super() + this.numWatchers = watcherOptionsList.length + this.watchers = [] + this.eventBuffers = {} + + watcherOptionsList.forEach(watcherOptions => + this.addWatcher(watcherOptions) + ) + } + + addWatcher(watcherOptions) { + const watcher = watch(watcherOptions) + this.watchers.push(watcher) + + watcher.on("event", event => { + const {code} = event + + switch (code) { + case "ERROR": + console.error("Build failed!", event.error) + break + } + + if (!this.eventBuffers[code]) this.eventBuffers[code] = new EventBuffer() + this.eventBuffers[code].put(watcher, event) + + if (this.eventBuffers[code].size >= this.numWatchers) { + this.emit("event", { + code, + events: this.eventBuffers[code], + }) + this.eventBuffers[code].clear() + } + }) + + return watcher + } +} + +class EventBuffer { + events = [] + + get(watcher) { + return this.events.find(evt => evt.watcher === watcher)?.event + } + + put(watcher, event) { + return this.events.push({ + watcher, + event, + }) + } + + clear() { + this.events = [] + } + + get size() { + return this.events.length + } +} + +module.exports = WatcherPool diff --git a/packages/fcl/package.json b/packages/fcl/package.json index 1a6e3ab11..1c90b8b74 100644 --- a/packages/fcl/package.json +++ b/packages/fcl/package.json @@ -30,7 +30,7 @@ "source": "src/fcl.js", "main": "dist/fcl.js", "module": "dist/fcl.module.js", - "unpkg": "dist/fcl.umd.js", + "unpkg": "dist/fcl.umd.min.js", "scripts": { "pain": "npm publish --tag pain", "alpha": "npm publish --tag alpha",