Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ Please refer to the linked documentation for using `arc` in each environment:
- Node 8+ ([`arc-server`](./packages/arc-server))
- Webpack 4+ ([`arc-webpack`](./packages/arc-webpack))
- Lasso 3+ ([`arc-lasso`](./packages/arc-lasso))
- Rollup 1+ ([`arc-rollup`](./packages/arc-rollup))

## Additional resources

Expand Down
72 changes: 72 additions & 0 deletions packages/arc-rollup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# arc-rollup

<a href="https://www.ebay.com">
<img src="https://img.shields.io/badge/ebay-open%20source-01d5c2.svg" alt="ebay open source"/>
</a>
<a href="https://img.shields.io/github/license/eBay/arc.svg">
<img src="https://img.shields.io/github/license/eBay/arc.svg" alt="MIT licensed"/>
</a>
<a href="https://travis-ci.org/eBay/arc">
<img src="https://travis-ci.org/eBay/arc.svg?branch=master" alt="travisci build"/>
</a>
<a href="https://codecov.io/gh/eBay/arc/list/master/packages/arc-rollup">
<img src="https://codecov.io/gh/eBay/arc/branch/master/graph/badge.svg" alt="Codecov" />
</a>
<a href="https://www.npmjs.com/package/arc-rollup">
<img src="https://img.shields.io/npm/v/arc-rollup.svg" alt="npm version"/>
</a>
<a href="http://npm-stat.com/charts.html?package=arc-rollup">
<img src="https://img.shields.io/npm/dm/arc-rollup.svg" alt="downloads"/>
</a>

## API

The `arc-rollup` plugin is a drop-in replacement for [`rollup-plugin-node-resolve`](https://github.com/rollup/rollup-plugin-node-resolve) that provides flag-based adaptive resolution in addition to node's [module resolution](https://nodejs.org/api/modules.html#modules_all_together). It is built on `rollup-plugin-node-resolve` and supports all the same options, plus the following:

### `flags`

The flagset to use when resolving adaptive files.

### `proxy` _(unstable)_

When `true`, compiles to use `arc-server/proxy` instead of resolving to a specfic resolution of an adaptive file. This only supports default exports for adaptive modules (named exports and commonjs are not supported). Until this limitation is addressed, it is recommended to use the `arc-server/install` hook when loading adaptive files in Node.js.

## Examples

### Create multiple bundles for different flagsets

```js
import resolve from "arc-rollup";

export default [{ desktop:true }, { mobile:true }].map(flags => ({
input: "main.js",
output: {
file: `bundle-${Object.keys(flags).join("-")}.js`,
format: "iife"
},
plugins: [
resolve({ flags })
]
});
```

### Bundle for Node.js

```js
import resolve from "arc-rollup";
import commonjs from "rollup-plugin-commonjs";
import builtins from "builtin-modules";

export default {
input: "server.js",
output: {
file: `bundle.js`,
format: "cjs"
},
plugins: [
resolve({ proxy:true }),
commonjs()
],
externals: builtins
};
```
80 changes: 80 additions & 0 deletions packages/arc-rollup/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const resolve = require("rollup-plugin-node-resolve");
const AdaptiveFS = require('arc-fs');
const PROXY_SUFFIX = "?arc-proxy";

module.exports = function({ proxy, flags, ...additionalOptions } = {}) {
if (!flags && !proxy) {
throw new Error("The arc-rollup plugin should be passed flags to be used when resolving files or proxy:true should be passed.")
}

const afs = new AdaptiveFS({ flags });
const plugin = resolve({
...additionalOptions,
customResolveOptions: {
...additionalOptions.customResolveOptions,
readFile: afs.readFile,
isFile(file, cb) {
afs.stat(file, function (err, stat) {
if (!err) {
return cb(null, stat.isFile() || stat.isFIFO());
}
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
return cb(err);
});
},
isDirectory(dir, cb) {
afs.stat(dir, function (err, stat) {
if (!err) {
return cb(null, stat.isDirectory());
}
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false);
return cb(err);
});
}
}
});

const originalResolveId = plugin.resolveId;
plugin.resolveId = async function (importee, importer) {
const result = await originalResolveId(importee, importer);
if (result && result.id) {
if (proxy) {
if (importer !== result.id + PROXY_SUFFIX && afs.isAdaptiveSync(result.id)) {
result.id += PROXY_SUFFIX
}
} else {
result.id = afs.resolveSync(result.id);
}
}
return result;
}

if (proxy) {
plugin.load = function (id) {
if (id.endsWith(PROXY_SUFFIX)) {
const file = id.slice(0, -PROXY_SUFFIX.length);
const matches = afs.getMatchesSync(file);
const code = `
import Proxy from "arc-server/proxy";
import { MatchSet } from "arc-resolver";
${
Array.from(matches).map(({ value }, index) => {
return `import * as target_${index} from ${JSON.stringify(value)};`;
}).join('\n')
}

const matches = new MatchSet([${
Array.from(matches).map(({ flags }, index) => {
return `{ value:target_${index}, flags:${JSON.stringify(flags)} }`;
}).join(',')
}]);

export default new Proxy(matches);
`;
return code;
}
}
}

return plugin;
}
21 changes: 21 additions & 0 deletions packages/arc-rollup/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "arc-rollup",
"version": "2.0.0",
"description": "Resolve adaptive modules when using Rollup",
"main": "index.js",
"author": "Michael Rawlings <ml.rawlings@gmail.com>",
"license": "MIT",
"dependencies": {
"arc-fs": "^2.0.0",
"rollup-plugin-node-resolve": "^5.2.0"
},
"devDependencies": {
"@babel/core": "^7.0.0-rc.1",
"@babel/preset-env": "^7.0.0-rc.1",
"arc-resolver": "^2.0.0",
"arc-server": "^2.0.0",
"builtin-modules": "^3.1.0",
"rollup": "^1.27.2",
"rollup-plugin-commonjs": "^10.1.0"
}
}
1 change: 1 addition & 0 deletions packages/arc-rollup/test/fixture-with-base/fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => console.log('mobile');
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => console.log('desktop');
2 changes: 2 additions & 0 deletions packages/arc-rollup/test/fixture-with-base/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import log from './fixture';
log();
1 change: 1 addition & 0 deletions packages/arc-rollup/test/fixture/fixture[desktop].js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => console.log('desktop');
1 change: 1 addition & 0 deletions packages/arc-rollup/test/fixture/fixture[mobile].js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => console.log('mobile');
2 changes: 2 additions & 0 deletions packages/arc-rollup/test/fixture/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import log from './fixture';
log();
59 changes: 59 additions & 0 deletions packages/arc-rollup/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
let rollup = require('rollup');
let commonjs = require('rollup-plugin-commonjs');
let builtins = require("builtin-modules");
let expect = require('chai').expect;
let resolve = require('../');

describe('resolve', () => {
describe('api', () => {
it('should throw if no flags are passed', () => {
expect(() => resolve()).to.throw(/flags/);
});
});

[
{
description: 'fixture (exclusive)',
input: require.resolve('./fixture')
},
{
description: 'fixture-with-base',
input: require.resolve('./fixture-with-base')
}
].forEach(({ description, input }) => {
describe(description, () => {
it('should work', async () => {
const bundle = await rollup.rollup({
input,
plugins: [resolve({ flags: { mobile: true } })]
});
const { output:[{ code }] } = await bundle.generate({ format: "iife" });
expect(code).to.not.include(`console.log('desktop')`);
expect(code).to.include(`console.log('mobile')`);
});
it('should work', async () => {
const bundle = await rollup.rollup({
input,
plugins: [resolve({ flags: { desktop: true } })]
});
const { output:[{ code }] } = await bundle.generate({ format: "iife" });
expect(code).to.include(`console.log('desktop')`);
expect(code).to.not.include(`console.log('mobile')`);
});
it('should bundle proxies for the server', async () => {
const bundle = await rollup.rollup({
input,
plugins: [
resolve({ proxy: true }),
commonjs()
],
external: builtins
});
const { output:[{ code }] } = await bundle.generate({ format: "esm" });
expect(code).to.include(`console.log('desktop')`);
expect(code).to.include(`console.log('mobile')`);
expect(code).to.include(`new Proxy`);
});
});
});
});