Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: inline syntax for sources (#310)
  • Loading branch information
evilebottnawi committed Aug 18, 2020
1 parent b92ed21 commit c247cfa
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 134 deletions.
11 changes: 11 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 @@ -75,6 +75,7 @@
"posthtml-webp": "^1.5.0",
"prettier": "^2.0.5",
"standard-version": "^8.0.2",
"url-loader": "^4.1.0",
"webpack": "^4.44.1"
},
"keywords": [
Expand Down
3 changes: 2 additions & 1 deletion src/index.js
@@ -1,4 +1,4 @@
import { getOptions } from 'loader-utils';
import { getOptions, stringifyRequest } from 'loader-utils';
import validateOptions from 'schema-utils';

import { sourcePlugin, minimizerPlugin } from './plugins';
Expand Down Expand Up @@ -35,6 +35,7 @@ export default async function loader(content) {
if (options.attributes) {
plugins.push(
sourcePlugin({
urlHandler: (url) => stringifyRequest(this, url),
attributes: options.attributes,
resourcePath: this.resourcePath,
imports,
Expand Down
169 changes: 83 additions & 86 deletions src/plugins/source-plugin.js
@@ -1,25 +1,14 @@
import { parse } from 'url';

import { Parser } from 'htmlparser2';
import { isUrlRequest, urlToRequest } from 'loader-utils';
import { isUrlRequest } from 'loader-utils';

import HtmlSourceError from '../HtmlSourceError';
import { getFilter, parseSrc, parseSrcset } from '../utils';

function parseSource(source) {
const URLObject = parse(source);
const { hash } = URLObject;

if (!hash) {
return { sourceValue: source };
}

URLObject.hash = null;

const sourceWithoutHash = URLObject.format();

return { sourceValue: sourceWithoutHash, hash };
}
import {
getFilter,
parseSrc,
parseSrcset,
normalizeUrl,
requestify,
} from '../utils';

export default (options) =>
function process(html) {
Expand All @@ -44,45 +33,6 @@ export default (options) =>
});
};
const { resourcePath } = options;
const imports = new Map();
const getImportItem = (value) => {
const key = urlToRequest(decodeURIComponent(value), root);

let name = imports.get(key);

if (name) {
return { key, name };
}

name = `___HTML_LOADER_IMPORT_${imports.size}___`;
imports.set(key, name);

options.imports.push({ importName: name, source: key });

return { key, name };
};
const replacements = new Map();
const getReplacementItem = (importItem, unquoted, hash) => {
const key = JSON.stringify({ key: importItem.key, unquoted, hash });

let name = replacements.get(key);

if (name) {
return { key, name };
}

name = `___HTML_LOADER_REPLACEMENT_${replacements.size}___`;
replacements.set(key, name);

options.replacements.push({
replacementName: name,
importName: importItem.name,
hash,
unquoted,
});

return { key, name };
};
const parser = new Parser(
{
attributesMeta: {},
Expand Down Expand Up @@ -135,21 +85,16 @@ export default (options) =>
return;
}

if (!urlFilter(attribute, source.value, resourcePath)) {
return;
}

const { sourceValue, hash } = parseSource(source.value);
const importItem = getImportItem(sourceValue);
const replacementItem = getReplacementItem(
importItem,
unquoted,
hash
);
const startIndex = valueStartIndex + source.startIndex;
const endIndex = startIndex + source.value.length;

sources.push({ replacementItem, startIndex, endIndex });
sources.push({
name: attribute,
value: source.value,
unquoted,
startIndex,
endIndex,
});

break;
}
Expand All @@ -173,22 +118,16 @@ export default (options) =>

sourceSet.forEach((sourceItem) => {
const { source } = sourceItem;

if (!urlFilter(attribute, source.value, resourcePath)) {
return;
}

const { sourceValue, hash } = parseSource(source.value);
const importItem = getImportItem(sourceValue);
const replacementItem = getReplacementItem(
importItem,
unquoted,
hash
);
const startIndex = valueStartIndex + source.startIndex;
const endIndex = startIndex + source.value.length;

sources.push({ replacementItem, startIndex, endIndex });
sources.push({
name: attribute,
value: source.value,
unquoted,
startIndex,
endIndex,
});
});

break;
Expand Down Expand Up @@ -261,18 +200,76 @@ export default (options) =>
parser.write(html);
parser.end();

const imports = new Map();
const replacements = new Map();

let offset = 0;

for (const source of sources) {
const { startIndex, endIndex, replacementItem } = source;
const { name, value, unquoted, startIndex, endIndex } = source;

let normalizedUrl = value;
let prefix = '';

const queryParts = normalizedUrl.split('!');

if (queryParts.length > 1) {
normalizedUrl = queryParts.pop();
prefix = queryParts.join('!');
}

normalizedUrl = normalizeUrl(normalizedUrl);

if (!urlFilter(name, value, resourcePath)) {
// eslint-disable-next-line no-continue
continue;
}

let hash;
const indexHash = normalizedUrl.lastIndexOf('#');

if (indexHash >= 0) {
hash = normalizedUrl.substr(indexHash, indexHash);
normalizedUrl = normalizedUrl.substr(0, indexHash);
}

const request = requestify(normalizedUrl, root);
const newUrl = prefix ? `${prefix}!${request}` : request;
const importKey = newUrl;
let importName = imports.get(importKey);

if (!importName) {
importName = `___HTML_LOADER_IMPORT_${imports.size}___`;
imports.set(importKey, importName);

options.imports.push({
importName,
source: options.urlHandler(newUrl),
});
}

const replacementKey = JSON.stringify({ newUrl, unquoted, hash });
let replacementName = replacements.get(replacementKey);

if (!replacementName) {
replacementName = `___HTML_LOADER_REPLACEMENT_${replacements.size}___`;
replacements.set(replacementKey, replacementName);

options.replacements.push({
replacementName,
importName,
hash,
unquoted,
});
}

// eslint-disable-next-line no-param-reassign
html =
html.slice(0, startIndex + offset) +
replacementItem.name +
replacementName +
html.slice(endIndex + offset);

offset += startIndex + replacementItem.name.length - endIndex;
offset += startIndex + replacementName.length - endIndex;
}

return html;
Expand Down
15 changes: 11 additions & 4 deletions src/utils.js
@@ -1,4 +1,4 @@
import { stringifyRequest } from 'loader-utils';
import { stringifyRequest, urlToRequest } from 'loader-utils';

function isASCIIWhitespace(character) {
return (
Expand Down Expand Up @@ -370,6 +370,14 @@ export function parseSrc(input) {
return { value, startIndex };
}

export function normalizeUrl(url) {
return decodeURIComponent(url);
}

export function requestify(url, root) {
return urlToRequest(url, root);
}

function isProductionMode(loaderContext) {
return loaderContext.mode === 'production' || !loaderContext.mode;
}
Expand Down Expand Up @@ -606,11 +614,10 @@ export function getImportCode(html, loaderContext, imports, options) {

for (const item of imports) {
const { importName, source } = item;
const stringifiedSourceRequest = stringifyRequest(loaderContext, source);

code += options.esModule
? `import ${importName} from ${stringifiedSourceRequest};\n`
: `var ${importName} = require(${stringifiedSourceRequest});\n`;
? `import ${importName} from ${source};\n`
: `var ${importName} = require(${source});\n`;
}

return `// Imports\n${code}`;
Expand Down

0 comments on commit c247cfa

Please sign in to comment.