Skip to content

Commit 385436e

Browse files
committed
Initial commit
0 parents  commit 385436e

File tree

9 files changed

+462
-0
lines changed

9 files changed

+462
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
package-lock.json

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Fuwei Chin
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# rollup-plugin-import-maps
2+
3+
A plugin to resolve ECMAScript module bare import specifiers at build-time for browsers which don't support import-maps, mostly based on **WICG's [import-maps reference implementation](https://github.com/WICG/import-maps/tree/master/reference-implementation)**.
4+
5+
6+
## Install
7+
8+
```sh
9+
npm install --save-dev rollup-plugin-import-maps
10+
```
11+
12+
## Usage
13+
14+
1. edit rollup.config.js, import and use the plugin
15+
16+
```js
17+
import { importMapsPlugin } from 'rollup-plugin-import-maps';
18+
import { readFileSync } from 'fs';
19+
20+
export default {
21+
input: './src/index.js',
22+
plugins: [
23+
importMapsPlugin({
24+
srcObject: process.env.ROLLUP_WATCH ? : readFileSync('./index-dev.importmap') : readFileSync('./index-cdn.importmap')
25+
})
26+
],
27+
output: {
28+
file: './dist/index.js',
29+
format: 'es'
30+
}
31+
};
32+
```
33+
34+
2. install some esm-ready packages, for example:
35+
36+
```sh
37+
npm install vue@2.x underscore@1.x
38+
```
39+
40+
3. create importmap files like index-dev.importmap
41+
42+
```json
43+
{
44+
"imports": {
45+
"vue": "/node_modules/vue/dist/vue.esm.browser.min.js",
46+
"underscore/": "/node_modules/underscore/",
47+
"@/polyfills/": "/lib/polyfills/"
48+
}
49+
}
50+
```
51+
52+
and index-cdn.importmap
53+
54+
```json
55+
{
56+
"imports": {
57+
"vue": "https://unpkg.com/vue@2.x/dist/vue.esm.browser.min.js",
58+
"underscore/": "https://unpkg.com/underscore@1.x/",
59+
"@/polyfills/": "/lib/polyfills/"
60+
}
61+
}
62+
```
63+
64+
4. Input file './src/index.js'
65+
66+
```js
67+
import Vue from 'vue';
68+
import shuffle from 'underscore/modules/shuffle.js';
69+
import '@/polyfills/navigator.userAgentData.js';
70+
// ...
71+
```
72+
73+
5. use rollup to watch or build
74+
75+
```sh
76+
rollup -c rollup.config.js -w
77+
# or
78+
rollup -c rollup.config.js
79+
```
80+
81+
6. Output code './dist/index.js'
82+
83+
```js
84+
import Vue from '/node_modules/vue/dist/vue.esm.browser.min.js';
85+
import shuffle from '/node_modules/underscore/modules/shuffle.js';
86+
import '/lib/polyfills/navigator.userAgentData.js';
87+
// ...
88+
```
89+
90+
or
91+
92+
```js
93+
import Vue from 'https://unpkg.com/vue@2.x/dist/vue.esm.browser.min.js';
94+
import shuffle from 'https://unpkg.com/underscore@1.x/modules/shuffle.js';
95+
import '/lib/polyfills/navigator.userAgentData.js';
96+
// ...
97+
```
98+
99+
### Plugin Options
100+
101+
+ `srcPath`:string optional
102+
103+
file path to importmap
104+
105+
+ `srcObject`:Buffer|ArrayBuffer|Object optional
106+
107+
raw buffer of importmap
108+
109+
+ `baseDir`: string default `process.cwd()`
110+
111+
baseDir to calculate scope paths in order to match scopes defined in importmap
112+
113+
**Note:** either srcPath or srcObject should be specified
114+
115+
116+
## License
117+
118+
[MIT](./LICENSE)
119+
120+
Other licenses of dependencies
121+
122+
+ import-maps: [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document) and [W3C CLA](https://www.w3.org/community/about/agreements/cla/)

dist/index.cjs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, '__esModule', { value: true });
4+
5+
var path = require('path');
6+
var fs = require('fs');
7+
var importMaps = require('import-maps');
8+
var schemaUtils = require('schema-utils');
9+
var url = require('url');
10+
11+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12+
13+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
14+
15+
/* eslint-env node */
16+
const __dirname$1 = path__default["default"].dirname(url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href))));
17+
const schema = JSON.parse(fs.readFileSync(path__default["default"].resolve(__dirname$1, '../src/schema.json'), {encoding:'utf8'}));
18+
19+
let validateRollupConfig = (rollupConfig, srcObject) => {
20+
let {external:isExternal} = rollupConfig;
21+
let checkSpecifiers = (imports) => {
22+
Object.keys(imports).forEach((specifier) => {
23+
if(isExternal(specifier)){
24+
console.warn('specifier "' + specifier + '" is already in rollup config external list');
25+
}
26+
});
27+
};
28+
checkSpecifiers(srcObject.imports);
29+
let {scopes} = srcObject;
30+
if(scopes){
31+
Object.keys(scopes).forEach((prefix) => {
32+
checkSpecifiers(scopes[prefix]);
33+
});
34+
}
35+
};
36+
37+
let isBareSpecifier = (str) => {
38+
return !(/^(\.\.?\/|\/)/.test(str) || /(https?:\/\/|data:|file:\/\/)/.test(str));
39+
};
40+
41+
function importMapsPlugin(options) {
42+
schemaUtils.validate(schema, options, {
43+
name: 'rollup-plugin-import-maps',
44+
baseDataPath: 'options'
45+
});
46+
const fakeBaseURL = 'https://fakepath';
47+
let {srcObject, srcPath, baseDir} = options;
48+
49+
let rawImportMaps = null;
50+
if(srcObject instanceof Buffer || srcObject instanceof ArrayBuffer || typeof srcObject === 'object'){
51+
// read buffer on buildStart
52+
}else if(typeof srcPath === 'string'){
53+
// read file on buildStart
54+
}else {
55+
throw new Error('Either srcObject or srcPath should be specified in options');
56+
}
57+
let parsedImportMaps = null;
58+
if(baseDir){
59+
baseDir = path__default["default"].resolve(baseDir);
60+
}
61+
let cache = {};
62+
let getFakeURL = (scriptFile) => {
63+
let scriptURL = cache[scriptFile];
64+
if(!scriptURL){
65+
let scriptPath = path__default["default"].relative(baseDir, scriptFile).replace(/\\/g, () => '/');
66+
scriptURL = new URL(scriptPath, fakeBaseURL);
67+
cache[scriptFile] = scriptURL;
68+
}
69+
return scriptURL;
70+
};
71+
let rollupConfig;
72+
73+
return {
74+
name: 'import-maps',
75+
async buildStart(config) {
76+
if(srcObject instanceof Buffer){
77+
rawImportMaps = srcObject.toString('utf8');
78+
}else if(srcObject instanceof ArrayBuffer){
79+
rawImportMaps = Buffer.from(srcObject).toString('utf8');
80+
}else if(typeof srcObject === 'object'){
81+
rawImportMaps = JSON.stringify(srcObject, null, 2);
82+
}else if(srcPath){
83+
if(!fs.existsSync(srcPath)){
84+
throw new Error(`options.srcPath "${srcPath}" doesn't denote a file`);
85+
}
86+
rawImportMaps = fs.readFileSync(srcPath, {encoding:'utf8'});
87+
}
88+
parsedImportMaps = importMaps.parseFromString(rawImportMaps, fakeBaseURL);
89+
validateRollupConfig(config, parsedImportMaps);
90+
if(!baseDir){
91+
baseDir = process.cwd();
92+
}
93+
rollupConfig = config;
94+
},
95+
resolveId(source, importer, info) {
96+
if(info.isEntry){
97+
return null;
98+
}
99+
if(isBareSpecifier(source) && importer){
100+
if(rollupConfig.external(source)){
101+
// console.warn(`skip specifier "${source}" from import-maps processing`);
102+
return null;
103+
}
104+
let scriptURL = getFakeURL(importer);
105+
const parsedUrl = importMaps.resolve(source, parsedImportMaps, scriptURL);
106+
let finalSpecifier = parsedUrl.origin === fakeBaseURL ? parsedUrl.href.slice(fakeBaseURL.length) :
107+
parsedUrl.href;
108+
return {
109+
id: finalSpecifier,
110+
external: 'absolute', // boolean or 'relative', 'absolute'
111+
};
112+
}
113+
return null;
114+
},
115+
};
116+
}
117+
118+
exports.importMapsPlugin = importMapsPlugin;

package.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "rollup-plugin-import-maps",
3+
"version": "0.1.0",
4+
"description": "A plugin to resolve ECMAScript module bare import specifiers at build-time",
5+
"keywords": [
6+
"rollup-plugin",
7+
"import-maps"
8+
],
9+
"author": "Fuwei Chin",
10+
"license": "MIT",
11+
"main": "dist/index.cjs",
12+
"type": "module",
13+
"types": "src/index.d.ts",
14+
"exports": {
15+
"import": "./src/index.mjs",
16+
"require": "./dist/index.cjs"
17+
},
18+
"engines": {
19+
"node": ">=14"
20+
},
21+
"files": [
22+
"src",
23+
"dist",
24+
"README.md"
25+
],
26+
"repository": {
27+
"type": "git",
28+
"url": "https://github.com/fuweichin/rollup-plugin-import-maps"
29+
},
30+
"scripts": {
31+
"build": "rollup -c rollup.config.js",
32+
"watch": "rollup -c rollup.config.js -w"
33+
},
34+
"dependencies": {
35+
"import-maps": "^0.2.4",
36+
"schema-utils": "^4.0.0"
37+
},
38+
"peerDependencies": {
39+
"rollup": ">=2.0"
40+
},
41+
"devDependencies": {
42+
"acorn-import-assertions": "^1.8.0",
43+
"rollup-plugin-import-assert": "^2.1.0"
44+
}
45+
}

rollup.config.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { importAssertions } from 'acorn-import-assertions';
2+
import { importAssertionsPlugin } from 'rollup-plugin-import-assert';
3+
4+
export default {
5+
input: 'src/index.mjs',
6+
external: ['path', 'url', 'fs', 'util', 'import-maps', 'schema-utils'],
7+
treeshake: false,
8+
acornInjectPlugins: [
9+
importAssertions
10+
],
11+
plugins: [
12+
importAssertionsPlugin(),
13+
],
14+
output: {
15+
file: 'dist/index.cjs',
16+
format: 'cjs'
17+
}
18+
};

src/index.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface Options {
2+
srcPath?: string,
3+
srcObject?: Buffer | Object,
4+
baseDir?: string,
5+
}
6+
export declare function importMapsPlugin(options: Options): Object;

0 commit comments

Comments
 (0)