|
| 1 | +--- |
| 2 | +title: Running Rollup in a Browser |
| 3 | +--- |
| 4 | + |
| 5 | +# {{ $frontmatter.title }} |
| 6 | + |
| 7 | +[[toc]] |
| 8 | + |
| 9 | +## The browser build |
| 10 | + |
| 11 | +While the regular Rollup build relies on some NodeJS builtin libraries, there is also a browser build available that only uses browser APIs. You can install it via |
| 12 | + |
| 13 | +```shell |
| 14 | +npm install @rollup/browser |
| 15 | +``` |
| 16 | + |
| 17 | +and in your script, import it via |
| 18 | + |
| 19 | +```js |
| 20 | +import { rollup } from '@rollup/browser'; |
| 21 | +``` |
| 22 | + |
| 23 | +Alternatively, you can import from a CDN, e.g. for the ESM build |
| 24 | + |
| 25 | +```js |
| 26 | +import * as rollup from 'https://unpkg.com/@rollup/browser/dist/es/rollup.browser.js'; |
| 27 | +``` |
| 28 | + |
| 29 | +and for the UMD build |
| 30 | + |
| 31 | +```html |
| 32 | +<script src="https://unpkg.com/@rollup/browser/dist/rollup.browser.js"></script> |
| 33 | +``` |
| 34 | + |
| 35 | +which will create a global variable `window.rollup`. Note that in each case, you need to make sure that the file `dist/bindings_wasm_bg.wasm` from the `@rollup/browser` package is served next to where the browser build is served. |
| 36 | + |
| 37 | +As the browser build cannot access the file system, you either need to provide an [in-memory file system](#using-an-in-memory-file-system) via the [`fs`](../configuration-options/index.md#fs) option, or you need to [provide plugins](#using-plugins-to-resolve-and-load-modules) that resolve and load all modules you want to bundle. |
| 38 | + |
| 39 | +## Using an in-memory file system |
| 40 | + |
| 41 | +Rollup allows you to provide an in-memory file system implementation that needs to implement at least a certain sub-set of the NodeJS `fs` API, cf. the [`fs`](../configuration-options/index.md#fs) option. This makes the browser build behave very similar to the NodeJS build and even allows you to use certain plugins that rely on the file system, provided they only access it via the [`this.fs`](../plugin-development/index.md#this-fs) plugin context property. Here is an example that uses [`memfs`](https://www.npmjs.com/package/memfs): |
| 42 | + |
| 43 | +```js twoslash |
| 44 | +/** @type {import('rollup')} */ |
| 45 | +var rollup; |
| 46 | +// ---cut--- |
| 47 | +import { rollup } from '@rollup/browser'; |
| 48 | +import { Volume } from 'memfs'; |
| 49 | + |
| 50 | +const vol = Volume.fromJSON({ |
| 51 | + '/main.js': "import foo from 'foo.js'; console.log(foo);", |
| 52 | + '/foo.js': 'export default 42;' |
| 53 | +}); |
| 54 | + |
| 55 | +rollup |
| 56 | + .rollup({ |
| 57 | + input: '/main.js', |
| 58 | + fs: vol.promises |
| 59 | + }) |
| 60 | + .then(bundle => bundle.generate({ format: 'es' })) |
| 61 | + .then(({ output }) => console.log(output[0].code)); |
| 62 | +``` |
| 63 | + |
| 64 | +## Using plugins to resolve and load modules |
| 65 | + |
| 66 | +You can also resolve and load all modules via plugins. Here is how you could do this: |
| 67 | + |
| 68 | +```js twoslash |
| 69 | +/** @type {import('rollup')} */ |
| 70 | +var rollup; |
| 71 | +// ---cut--- |
| 72 | +const modules = { |
| 73 | + 'main.js': "import foo from 'foo.js'; console.log(foo);", |
| 74 | + 'foo.js': 'export default 42;' |
| 75 | +}; |
| 76 | + |
| 77 | +rollup |
| 78 | + .rollup({ |
| 79 | + input: 'main.js', |
| 80 | + plugins: [ |
| 81 | + { |
| 82 | + name: 'loader', |
| 83 | + resolveId(source) { |
| 84 | + if (modules.hasOwnProperty(source)) { |
| 85 | + return source; |
| 86 | + } |
| 87 | + }, |
| 88 | + load(id) { |
| 89 | + if (modules.hasOwnProperty(id)) { |
| 90 | + return modules[id]; |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | + ] |
| 95 | + }) |
| 96 | + .then(bundle => bundle.generate({ format: 'es' })) |
| 97 | + .then(({ output }) => console.log(output[0].code)); |
| 98 | +``` |
| 99 | + |
| 100 | +This example only supports two imports, `"main.js"` and `"foo.js"`, and no relative imports. Here is another example that uses absolute URLs as entry points and supports relative imports. In that case, we are just re-bundling Rollup itself, but it could be used on any other URL that exposes an ES module: |
| 101 | + |
| 102 | +```js twoslash |
| 103 | +/** @type {import('rollup')} */ |
| 104 | +var rollup; |
| 105 | +// ---cut--- |
| 106 | +rollup |
| 107 | + .rollup({ |
| 108 | + input: 'https://unpkg.com/rollup/dist/es/rollup.js', |
| 109 | + plugins: [ |
| 110 | + { |
| 111 | + name: 'url-resolver', |
| 112 | + resolveId(source, importer) { |
| 113 | + if (source[0] !== '.') { |
| 114 | + try { |
| 115 | + new URL(source); |
| 116 | + // If it is a valid URL, return it |
| 117 | + return source; |
| 118 | + } catch { |
| 119 | + // Otherwise make it external |
| 120 | + return { id: source, external: true }; |
| 121 | + } |
| 122 | + } |
| 123 | + return new URL(source, importer).href; |
| 124 | + }, |
| 125 | + async load(id) { |
| 126 | + const response = await fetch(id); |
| 127 | + return response.text(); |
| 128 | + } |
| 129 | + } |
| 130 | + ] |
| 131 | + }) |
| 132 | + .then(bundle => bundle.generate({ format: 'es' })) |
| 133 | + .then(({ output }) => console.log(output)); |
| 134 | +``` |
0 commit comments