Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat remote resources #113

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
149 changes: 149 additions & 0 deletions README.md
Expand Up @@ -58,6 +58,155 @@ Be mindful in setting [include](https://webpack.js.org/configuration/module/#rul

And run `webpack` via your preferred method.

## Options

### `brokenMapUrlReportType`

Type: `String`
Default: `warning`

Type of error message, when the map failed to load.

Possible values:

- `ignore`
- `warning`
- `error`

**webpack.config.js**

```js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
use: [
{
loader: 'source-map-loader',
options: {
brokenMapUrlReportType: 'ignore',
},
},
],
},
],
},
};
```

### `brokenMapParseReportType`

Type: `String`
Default: `warning`

Type of error message, when the card is received, but cannot be correctly parsed.

Possible values:

- `ignore`
- `warning`
- `error`

**webpack.config.js**

```js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
use: [
{
loader: 'source-map-loader',
options: {
brokenMapParseReportType: 'ignore',
},
},
],
},
],
},
};
```

### `brokenSourceUrlReportType`

Type: `String`
Default: `warning`

Type of error message, when the source (from `map.sources`) failed to load.

Possible values:

- `ignore`
- `warning`
- `error`

**webpack.config.js**

```js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
use: [
{
loader: 'source-map-loader',
options: {
brokenSourceUrlReportType: 'ignore',
},
},
],
},
],
},
};
```

### `unresolveSourceFetcher`

Type: `Function`
Default: `undefined`

The option allows you to fetching the remote content.

**webpack.config.js**

```js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
use: [
{
loader: 'source-map-loader',
options: {
async unresolveSourceFetcher(url) {
if (/^https?:\/\//i.test(url)) {
const response = await fetch(url);
const result = await response.text();

return result;
}

throw new Error(`${url} is not supported`);
},
},
},
],
},
],
},
};
```

## Contributing

Please take a moment to read our contributing guidelines if you haven't yet done so.
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -66,6 +66,7 @@
"jest": "^26.0.1",
"lint-staged": "^10.2.2",
"memfs": "^3.1.2",
"node-fetch": "^2.6.0",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.5",
"standard-version": "^8.0.0",
Expand Down
33 changes: 27 additions & 6 deletions src/index.js
Expand Up @@ -8,7 +8,12 @@ import validateOptions from 'schema-utils';
import { getOptions } from 'loader-utils';

import schema from './options.json';
import { getSourceMappingURL, fetchFromURL, flattenSourceMap } from './utils';
import {
getSourceMappingURL,
fetchFromURL,
flattenSourceMap,
getErrorReporter,
} from './utils';

export default async function loader(input, inputMap) {
const options = getOptions(this);
Expand All @@ -34,10 +39,17 @@ export default async function loader(input, inputMap) {
({ sourceURL, sourceContent } = await fetchFromURL(
this,
this.context,
sourceMappingURL
sourceMappingURL,
'',
false,
options.unresolveSourceFetcher
));
} catch (error) {
this.emitWarning(error);
const brokenMapUrlReporter = getErrorReporter(
this,
options.brokenMapUrlReportType
);
brokenMapUrlReporter(error);

callback(null, input, inputMap);

Expand All @@ -53,7 +65,11 @@ export default async function loader(input, inputMap) {
try {
map = JSON.parse(sourceContent.replace(/^\)\]\}'/, ''));
} catch (parseError) {
this.emitWarning(
const brokenMapParseReporter = getErrorReporter(
this,
options.brokenMapParseReportType
);
brokenMapParseReporter(
new Error(`Cannot parse source map from '${sourceURL}': ${parseError}`)
);

Expand Down Expand Up @@ -88,10 +104,15 @@ export default async function loader(input, inputMap) {
context,
source,
map.sourceRoot,
skipReading
skipReading,
options.unresolveSourceFetcher
));
} catch (error) {
this.emitWarning(error);
const brokenSourceUrlReporter = getErrorReporter(
this,
options.brokenSourceUrlReportType
);
brokenSourceUrlReporter(error);

sourceURL = source;
}
Expand Down
14 changes: 14 additions & 0 deletions src/options.json
@@ -1,4 +1,18 @@
{
"type": "object",
"properties": {
"brokenMapUrlReportType": {
"enum": ["ignore", "warning", "error"]
},
"brokenMapParseReportType": {
"enum": ["ignore", "warning", "error"]
},
"brokenSourceUrlReportType": {
"enum": ["ignore", "warning", "error"]
},
"unresolveSourceFetcher": {
"instanceof": "Function"
}
},
"additionalProperties": false
}
37 changes: 31 additions & 6 deletions src/utils.js
Expand Up @@ -60,9 +60,7 @@ async function flattenSourceMap(map) {
},
};

if (source) {
generatedMap.addMapping(mappings);
}
generatedMap.addMapping(mappings);
});

return generatedMap.toJSON();
Expand All @@ -80,7 +78,7 @@ function getSourceMappingURL(code) {
}

return {
sourceMappingURL: match ? match[1] || match[2] || '' : null,
sourceMappingURL: match ? match[1] || match[2] : null,
replacementString: match ? match[0] : null,
};
}
Expand Down Expand Up @@ -137,7 +135,8 @@ async function fetchFromURL(
context,
url,
sourceRoot,
skipReading = false
skipReading,
unresolveSourceFetcher
) {
// 1. It's an absolute url and it is not `windows` path like `C:\dir\file`
if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !path.win32.isAbsolute(url)) {
Expand All @@ -163,6 +162,16 @@ async function fetchFromURL(
return { sourceURL, sourceContent };
}

if (skipReading) {
return { sourceURL: url, sourceContent: '' };
}

if (unresolveSourceFetcher) {
const sourceContent = await unresolveSourceFetcher(url);

return { sourceURL: url, sourceContent };
}

throw new Error(`Absolute '${url}' URL is not supported`);
}

Expand Down Expand Up @@ -196,4 +205,20 @@ async function fetchFromURL(
return { sourceURL, sourceContent };
}

export { getSourceMappingURL, fetchFromURL, flattenSourceMap };
function getErrorReporter(loaderContext, typeReport) {
switch (typeReport) {
case 'error':
return loaderContext.emitError;
case 'ignore':
return function ignore() {};
default:
return loaderContext.emitWarning;
}
}

export {
getSourceMappingURL,
fetchFromURL,
flattenSourceMap,
getErrorReporter,
};