├── LICENSE ├── README.md ├── index.js └── test ├── hello.jsx └── index.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jed Schmidt 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esbuild-plugin-http-fetch 2 | 3 | An esbuild plugin that resolves http(s) modules, for use with browsers and Deno. 4 | 5 | ## Example 6 | ```js 7 | // test/index.js 8 | import {build, stop} from 'https://deno.land/x/esbuild@v0.12.1/mod.js' 9 | import httpFetch from 'https://deno.land/x/esbuild_plugin_http_fetch@v1.0.2/index.js' 10 | 11 | let {outputFiles} = await build({ 12 | bundle: true, 13 | entryPoints: ['test/hello.jsx'], 14 | jsxFactory: 'h', 15 | plugins: [httpFetch], 16 | write: false 17 | }) 18 | 19 | eval(outputFiles[0].text) 20 | // expected:

Hello, world!

21 | // actual:

Hello, world!

22 | 23 | stop() 24 | ``` 25 | 26 | ```js 27 | // test/hello.jsx 28 | import {h} from 'https://unpkg.com/preact@10.5.13/dist/preact.module.js' 29 | import render from 'https://unpkg.com/preact-render-to-string@5.1.19/dist/index.module.js?module' 30 | 31 | let app =

Hello, world!

32 | let html = render(app) 33 | 34 | console.log('expected: %s', '

Hello, world!

') 35 | console.log('actual: %s', html) 36 | ``` 37 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let name = 'http-fetch' 2 | 3 | let setup = ({onResolve, onLoad}) => { 4 | onResolve({filter: /^https:\/\//}, resolveFile) 5 | onResolve({filter: /.*/, namespace: 'http-fetch'}, resolveUrl) 6 | onLoad({filter: /.*/, namespace: 'http-fetch'}, loadSource) 7 | } 8 | 9 | let resolveFile = ({path}) => ({ 10 | path: path, 11 | namespace: 'http-fetch' 12 | }) 13 | 14 | let resolveUrl = ({path, importer}) => ({ 15 | path: new URL(path, importer).href, 16 | namespace: 'http-fetch' 17 | }) 18 | 19 | let loadSource = async ({path}) => { 20 | let source = await fetch(path) 21 | 22 | if (!source.ok) { 23 | let message = `GET ${path} failed: status ${source.status}` 24 | throw new Error(message) 25 | } 26 | 27 | let contents = await source.text() 28 | let pattern = /\/\/# sourceMappingURL=(\S+)/ 29 | let match = contents.match(pattern) 30 | if (match) { 31 | let url = new URL(match[1], source.url) 32 | let dataurl = await loadMap(url) 33 | let comment = `//# sourceMappingURL=${dataurl}` 34 | contents = contents.replace(pattern, comment) 35 | } 36 | 37 | let {pathname} = new URL(source.url) 38 | let loader = pathname.match(/[^.]+$/)[0] 39 | 40 | return {contents, loader} 41 | } 42 | 43 | let loadMap = async url => { 44 | let map = await fetch(url) 45 | let type = map.headers.get('content-type').replace(/\s/g, '') 46 | let buffer = await map.arrayBuffer() 47 | let blob = new Blob([buffer], {type}) 48 | let reader = new FileReader() 49 | return new Promise(cb => { 50 | reader.onload = e => cb(e.target.result) 51 | reader.readAsDataURL(blob) 52 | }) 53 | } 54 | 55 | export default {name, setup} 56 | -------------------------------------------------------------------------------- /test/hello.jsx: -------------------------------------------------------------------------------- 1 | import {h} from 'https://unpkg.com/preact@10.5.13/dist/preact.module.js' 2 | import render from 'https://unpkg.com/preact-render-to-string@5.1.19/dist/index.module.js?module' 3 | 4 | let app =

Hello, world!

5 | let html = render(app) 6 | 7 | console.log('expected: %s', '

Hello, world!

') 8 | console.log('actual: %s', html) 9 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import {build, stop} from 'https://deno.land/x/esbuild@v0.12.1/mod.js' 2 | import httpFetch from '../http-fetch.js' 3 | 4 | let {outputFiles} = await build({ 5 | bundle: true, 6 | entryPoints: ['test/hello.jsx'], 7 | jsxFactory: 'h', 8 | plugins: [httpFetch], 9 | write: false 10 | }) 11 | 12 | eval(outputFiles[0].text) 13 | // expected:

Hello, world!

14 | // actual:

Hello, world!

15 | 16 | stop() 17 | --------------------------------------------------------------------------------