Skip to content

Commit 6a749d3

Browse files
committed
feat: add rollup plugin
1 parent 8efbd9c commit 6a749d3

File tree

12 files changed

+240
-123
lines changed

12 files changed

+240
-123
lines changed

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ yarn add import-http --dev
3131

3232
## Usage
3333

34+
### Webpack
35+
3436
In your `webpack.config.js`:
3537

3638
```js
37-
const ImportHttpPlugin = require('import-http')
39+
const ImportHttpWebpackPlugin = require('import-http/webpack')
3840

3941
module.exports = {
40-
plugins: [new ImportHttpPlugin()]
42+
plugins: [new ImportHttpWebpackPlugin()]
4143
}
4244
```
4345

@@ -52,16 +54,26 @@ console.log(React, Vue)
5254

5355
Run webpack and it just works.
5456

57+
### Rollup
58+
59+
In your `rollup.config.js`:
60+
61+
```js
62+
export default {
63+
plugins: [require('import-http/rollup')()]
64+
}
65+
```
66+
5567
## Caching
5668

5769
Resources will be fetched at the very first build, then the response will be cached in `~/.import-http` dir. You can use the `reload` option to invalidate cache:
5870

5971
```js
60-
const ImportHttpPlugin = require('import-http')
72+
const ImportHttpWebpackPlugin = require('import-http/webpack')
6173

6274
module.exports = {
6375
plugins: [
64-
new ImportHttpPlugin({
76+
new ImportHttpWebpackPlugin({
6577
reload: process.env.RELOAD
6678
})
6779
]

example/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const ImportHttpPlugin = require('..')
1+
const ImportHttpPlugin = require('../webpack')
22

33
module.exports = {
44
mode: 'development',

lib/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const os = require('os')
2+
const path = require('path')
3+
4+
exports.CACHE_DIR = path.join(os.homedir(), '.import-http')

lib/fetch.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const fetch = require('node-fetch')
2+
3+
module.exports = async (url, opts) => {
4+
console.log(`Downloading ${url}...`)
5+
const res = await fetch(url, opts)
6+
if (!res.ok) {
7+
console.error(`Failed to download ${url}...`)
8+
throw new Error(res.statusText)
9+
}
10+
return res
11+
}

lib/index.js

Lines changed: 6 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,8 @@
1-
const os = require('os')
2-
const path = require('path')
3-
const { parse: parseURL, resolve: resolveURL } = require('url')
4-
const fetch = require('node-fetch')
5-
const builtinModules = require('builtin-modules')
6-
const { pathExists, outputFile } = require('./utils')
7-
const createHttpCache = require('./http-cache')
8-
9-
const RESOLVER_ID = 'import-http-resolver'
10-
11-
const HTTP_RE = /^https?:\/\//
12-
13-
class ImportHttpPlugin {
14-
constructor(options = {}) {
15-
this.reload = options.reload
16-
this.cacheDir = options.cacheDir
17-
? path.resolve(options.cacheDir)
18-
: path.join(os.homedir(), '.import-http')
19-
this.depsDir = path.join(this.cacheDir, 'deps')
20-
this.httpCache = createHttpCache(path.join(this.cacheDir, 'requests.json'))
21-
// Map<file, moduleId>
22-
this.fileModuleCache = new Map()
23-
}
24-
25-
getFilePathFromURL(url) {
26-
const { host, pathname, protocol } = parseURL(url)
27-
// Where should this url be in the disk
28-
return path.join(this.depsDir, protocol.replace(':', ''), host, pathname)
29-
}
30-
31-
apply(compiler) {
32-
compiler.resolverFactory.hooks.resolver
33-
.for('normal')
34-
.tap(RESOLVER_ID, resolver => {
35-
const resolvedHook = resolver.ensureHook(`resolve`)
36-
37-
resolver
38-
.getHook(`described-resolve`)
39-
.tapAsync(
40-
RESOLVER_ID,
41-
async (requestContext, resolveContext, callback) => {
42-
let id = requestContext.request
43-
const { issuer } = requestContext.context
44-
45-
// if the issuer is a URL (cached in deps dir)
46-
// resolve the url
47-
if (
48-
!HTTP_RE.test(id) &&
49-
issuer &&
50-
this.fileModuleCache.has(issuer) &&
51-
!this.fileModuleCache.has(id)
52-
) {
53-
if (/^\./.test(id)) {
54-
// Relative file
55-
// Excluded something like ./node_modules/webpack/buildin/global.js
56-
if (!/node_modules/.test(id)) {
57-
id = resolveURL(this.fileModuleCache.get(issuer), id)
58-
}
59-
} else if (!builtinModules.includes(id)) {
60-
// Propably an npm package
61-
id = `https://unpkg.com/${id}`
62-
}
63-
}
64-
65-
if (!HTTP_RE.test(id)) {
66-
return callback()
67-
}
68-
69-
const canResolve = (request, url) => {
70-
this.fileModuleCache.set(request, url)
71-
resolver.doResolve(
72-
resolvedHook,
73-
Object.assign({}, requestContext, {
74-
request
75-
}),
76-
null,
77-
resolveContext,
78-
callback
79-
)
80-
}
81-
82-
try {
83-
// Let's get the actual URL
84-
const url = await this.httpCache.get(id)
85-
let file
86-
87-
if (url && !this.reload) {
88-
file = this.getFilePathFromURL(url)
89-
if (await pathExists(file)) {
90-
return canResolve(file, url)
91-
}
92-
}
93-
94-
// We have never requested this before
95-
console.log(`Downloading ${id}...`)
96-
const res = await fetch(id)
97-
if (!res.ok) {
98-
console.error(`Failed to download ${id}...`)
99-
throw new Error(res.statusText)
100-
}
101-
file = this.getFilePathFromURL(res.url)
102-
await this.httpCache.set(id, res.url)
103-
const content = await res
104-
.buffer()
105-
.then(buff => buff.toString('utf8'))
106-
await outputFile(file, content, 'utf8')
107-
canResolve(file, res.url)
108-
} catch (error) {
109-
callback(error)
110-
}
111-
}
112-
)
113-
})
1+
module.exports = {
2+
get WebpackPlugin() {
3+
return require('./webpack')
4+
},
5+
get rollupPlugin() {
6+
return require('./rollup')
1147
}
1158
}
116-
117-
module.exports = ImportHttpPlugin

lib/rollup.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const path = require('path')
2+
const { parse: parseURL } = require('url')
3+
const {
4+
outputFile,
5+
pathExists,
6+
readFile,
7+
HTTP_RE,
8+
resolveURL
9+
} = require('./utils')
10+
const createHttpCache = require('./http-cache')
11+
const { CACHE_DIR } = require('./constants')
12+
const fetch = require('./fetch')
13+
14+
const PREFIX = '\0'
15+
16+
const removePrefix = id => id && id.replace(/^\0/, '')
17+
18+
const shouldLoad = id => {
19+
return HTTP_RE.test(removePrefix(id))
20+
}
21+
22+
module.exports = ({ reload, cacheDir = CACHE_DIR } = {}) => {
23+
const DEPS_DIR = path.join(cacheDir, 'deps')
24+
const HTTP_CACHE_FILE = path.join(cacheDir, 'requests.json')
25+
26+
const getFilePathFromURL = url => {
27+
const { host, pathname, protocol } = parseURL(url)
28+
// Where should this url be in the disk
29+
return path.join(DEPS_DIR, protocol.replace(':', ''), host, pathname)
30+
}
31+
32+
const httpCache = createHttpCache(HTTP_CACHE_FILE)
33+
34+
return {
35+
name: 'http',
36+
37+
async resolveId(importee, importer) {
38+
// We're importing from URL
39+
if (HTTP_RE.test(importee)) {
40+
return PREFIX + importee
41+
}
42+
43+
// We're importing a file but the importer the a URL
44+
// Then we should do
45+
if (importer) {
46+
importer = importer.replace(/^\0/, '')
47+
if (HTTP_RE.test(importer)) {
48+
return resolveURL(importer, importee)
49+
}
50+
}
51+
},
52+
53+
async load(id) {
54+
if (!shouldLoad(id)) return
55+
56+
id = removePrefix(id)
57+
const url = await httpCache.get(id)
58+
let file
59+
60+
if (url && !reload) {
61+
file = getFilePathFromURL(url)
62+
if (await pathExists(file)) {
63+
return readFile(file, 'utf8')
64+
}
65+
}
66+
67+
// We have never requested this before
68+
const res = await fetch(url)
69+
file = getFilePathFromURL(res.url)
70+
await httpCache.set(id, res.url)
71+
const content = await res.buffer().then(buff => buff.toString('utf8'))
72+
await outputFile(file, content, 'utf8')
73+
74+
return content
75+
}
76+
}
77+
}

lib/utils.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
const path = require('path')
22
const util = require('util')
33
const fs = require('fs')
4+
const url = require('url')
5+
const builtinModules = require('builtin-modules')
46

57
const mkdir = util.promisify(require('mkdirp'))
68

@@ -18,3 +20,19 @@ exports.pathExists = fp =>
1820
resolve(!err)
1921
})
2022
})
23+
24+
exports.HTTP_RE = /^https?:\/\//
25+
26+
exports.resolveURL = (issuer, id) => {
27+
if (/^\./.test(id)) {
28+
// Relative file
29+
// Excluded something like ./node_modules/webpack/buildin/global.js
30+
if (!/node_modules/.test(id)) {
31+
id = url.resolve(issuer, id)
32+
}
33+
} else if (!builtinModules.includes(id)) {
34+
// Propably an npm package
35+
id = `https://unpkg.com/${id}`
36+
}
37+
return id
38+
}

0 commit comments

Comments
 (0)