Skip to content

Commit

Permalink
refactor: code (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Aug 12, 2020
1 parent 03152b1 commit 3584ae6
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 218 deletions.
32 changes: 12 additions & 20 deletions src/index.js
Expand Up @@ -2,10 +2,9 @@ import { getOptions } from 'loader-utils';
import validateOptions from 'schema-utils';

import { sourcePlugin, minimizerPlugin } from './plugins';

import {
pluginRunner,
isProductionMode,
normalizeOptions,
getImportCode,
getModuleCode,
getExportCode,
Expand All @@ -14,13 +13,15 @@ import {
import schema from './options.json';

export default async function loader(content) {
const options = getOptions(this);
const rawOptions = getOptions(this);

validateOptions(schema, options, {
validateOptions(schema, rawOptions, {
name: 'HTML Loader',
baseDataPath: 'options',
});

const options = normalizeOptions(rawOptions, this);

if (options.preprocessor) {
// eslint-disable-next-line no-param-reassign
content = await options.preprocessor(content, this);
Expand All @@ -31,13 +32,10 @@ export default async function loader(content) {
const imports = [];
const replacements = [];

const attributes =
typeof options.attributes === 'undefined' ? true : options.attributes;

if (attributes) {
if (options.attributes) {
plugins.push(
sourcePlugin({
attributes,
attributes: options.attributes,
resourcePath: this.resourcePath,
imports,
errors,
Expand All @@ -46,13 +44,8 @@ export default async function loader(content) {
);
}

const minimize =
typeof options.minimize === 'undefined'
? isProductionMode(this)
: options.minimize;

if (minimize) {
plugins.push(minimizerPlugin({ minimize, errors }));
if (options.minimize) {
plugins.push(minimizerPlugin({ minimize: options.minimize, errors }));
}

const { html } = pluginRunner(plugins).process(content);
Expand All @@ -61,10 +54,9 @@ export default async function loader(content) {
this.emitError(error instanceof Error ? error : new Error(error));
}

const codeOptions = { ...options, loaderContext: this };
const importCode = getImportCode(html, imports, codeOptions);
const moduleCode = getModuleCode(html, replacements, codeOptions);
const exportCode = getExportCode(html, codeOptions);
const importCode = getImportCode(html, this, imports, options);
const moduleCode = getModuleCode(html, replacements, options);
const exportCode = getExportCode(html, options);

return `${importCode}${moduleCode}${exportCode}`;
}
25 changes: 1 addition & 24 deletions src/plugins/minimizer-plugin.js
Expand Up @@ -2,32 +2,9 @@ import { minify } from 'html-minifier-terser';

export default (options) =>
function process(html) {
const minimizeOptions =
typeof options.minimize === 'boolean' ||
typeof options.minimize === 'undefined'
? {
caseSensitive: true,
// `collapseBooleanAttributes` is not always safe, since this can break CSS attribute selectors and not safe for XHTML
collapseWhitespace: true,
conservativeCollapse: true,
keepClosingSlash: true,
// We need ability to use cssnano, or setup own function without extra dependencies
minifyCSS: true,
minifyJS: true,
// `minifyURLs` is unsafe, because we can't guarantee what the base URL is
// `removeAttributeQuotes` is not safe in some rare cases, also HTML spec recommends against doing this
removeComments: true,
// `removeEmptyAttributes` is not safe, can affect certain style or script behavior
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
// `useShortDoctype` is not safe for XHTML
}
: options.minimize;

try {
// eslint-disable-next-line no-param-reassign
html = minify(html, minimizeOptions);
html = minify(html, options.minimize);
} catch (error) {
options.errors.push(error);
}
Expand Down
148 changes: 2 additions & 146 deletions src/plugins/source-plugin.js
Expand Up @@ -6,136 +6,6 @@ import { isUrlRequest, urlToRequest } from 'loader-utils';
import HtmlSourceError from '../HtmlSourceError';
import { getFilter, parseSrc, parseSrcset } from '../utils';

function getAttributeValue(attributes, name) {
const lowercasedAttributes = Object.keys(attributes).reduce((keys, k) => {
// eslint-disable-next-line no-param-reassign
keys[k.toLowerCase()] = k;

return keys;
}, {});

return attributes[lowercasedAttributes[name.toLowerCase()]];
}

const defaultAttributes = [
{
tag: 'audio',
attribute: 'src',
type: 'src',
},
{
tag: 'embed',
attribute: 'src',
type: 'src',
},
{
tag: 'img',
attribute: 'src',
type: 'src',
},
{
tag: 'img',
attribute: 'srcset',
type: 'srcset',
},
{
tag: 'input',
attribute: 'src',
type: 'src',
},
{
tag: 'link',
attribute: 'href',
type: 'src',
filter: (tag, attribute, attributes) => {
if (!/stylesheet/i.test(getAttributeValue(attributes, 'rel'))) {
return false;
}

if (
attributes.type &&
getAttributeValue(attributes, 'type').trim().toLowerCase() !==
'text/css'
) {
return false;
}

return true;
},
},
{
tag: 'object',
attribute: 'data',
type: 'src',
},
{
tag: 'script',
attribute: 'src',
type: 'src',
filter: (tag, attribute, attributes) => {
if (attributes.type) {
const type = getAttributeValue(attributes, 'type').trim().toLowerCase();

if (
type !== 'module' &&
type !== 'text/javascript' &&
type !== 'application/javascript'
) {
return false;
}
}

return true;
},
},
{
tag: 'source',
attribute: 'src',
type: 'src',
},
{
tag: 'source',
attribute: 'srcset',
type: 'srcset',
},
{
tag: 'track',
attribute: 'src',
type: 'src',
},
{
tag: 'video',
attribute: 'poster',
type: 'src',
},
{
tag: 'video',
attribute: 'src',
type: 'src',
},
// SVG
{
tag: 'image',
attribute: 'xlink:href',
type: 'src',
},
{
tag: 'image',
attribute: 'href',
type: 'src',
},
{
tag: 'use',
attribute: 'xlink:href',
type: 'src',
},
{
tag: 'use',
attribute: 'href',
type: 'src',
},
];

function parseSource(source) {
const URLObject = parse(source);
const { hash } = URLObject;
Expand All @@ -153,27 +23,13 @@ function parseSource(source) {

export default (options) =>
function process(html) {
let attributeList;
let maybeUrlFilter;
let root;

if (
typeof options.attributes === 'undefined' ||
options.attributes === true
) {
attributeList = defaultAttributes;
} else {
attributeList = options.attributes.list || defaultAttributes;
// eslint-disable-next-line no-undefined
({ urlFilter: maybeUrlFilter, root } = options.attributes);
}

const { list, urlFilter: maybeUrlFilter, root } = options.attributes;
const sources = [];
const urlFilter = getFilter(maybeUrlFilter, (value) =>
isUrlRequest(value, root)
);
const getAttribute = (tag, attribute, attributes, resourcePath) => {
return attributeList.find((element) => {
return list.find((element) => {
const foundTag =
typeof element.tag === 'undefined' ||
(typeof element.tag !== 'undefined' &&
Expand Down

0 comments on commit 3584ae6

Please sign in to comment.