Skip to content

Commit 578c84d

Browse files
fix: reduce size of generated modules (#220)
1 parent b974ecb commit 578c84d

File tree

8 files changed

+66
-60
lines changed

8 files changed

+66
-60
lines changed

src/index.js

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ import { parse } from 'url';
22

33
import { compile } from 'es6-templates';
44
import { minify } from 'html-minifier-terser';
5-
import { getOptions, isUrlRequest, urlToRequest } from 'loader-utils';
5+
import { getOptions, isUrlRequest } from 'loader-utils';
66

77
import validateOptions from 'schema-utils';
88

9-
import { GET_URL_CODE, IDENT_REGEX, REQUIRE_REGEX } from './constants';
9+
import { REQUIRE_REGEX } from './constants';
1010
import {
11-
getExportsString,
1211
getLinks,
1312
getUniqueIdent,
1413
replaceLinkWithIdent,
1514
isProductionMode,
15+
getImportCode,
16+
getExportCode,
1617
} from './utils';
1718

1819
import schema from './options.json';
@@ -30,7 +31,7 @@ export default function htmlLoader(source) {
3031
let content = source.toString();
3132

3233
const links = getLinks(content, options.attributes);
33-
const data = new Map();
34+
const replacers = new Map();
3435

3536
let offset = 0;
3637
for (const link of links) {
@@ -47,9 +48,9 @@ export default function htmlLoader(source) {
4748
link.length = link.value.length;
4849
}
4950

50-
const ident = getUniqueIdent(data);
51+
const ident = getUniqueIdent(replacers);
5152

52-
data.set(ident, link.value);
53+
replacers.set(ident, link.value);
5354

5455
content = replaceLinkWithIdent(content, link, ident, offset);
5556

@@ -74,9 +75,9 @@ export default function htmlLoader(source) {
7475
reqList.reverse();
7576

7677
for (const link of reqList) {
77-
const ident = getUniqueIdent(data);
78+
const ident = getUniqueIdent(replacers);
7879

79-
data.set(ident, link.value.substring(11, link.length - 3));
80+
replacers.set(ident, link.value.substring(11, link.length - 3));
8081

8182
content = replaceLinkWithIdent(content, link, ident);
8283
}
@@ -117,21 +118,8 @@ export default function htmlLoader(source) {
117118
content = JSON.stringify(content);
118119
}
119120

120-
const exportsString = getExportsString(options);
121+
const importCode = getImportCode(replacers);
122+
const exportCode = getExportCode(content, replacers, options);
121123

122-
return `${GET_URL_CODE +
123-
exportsString +
124-
content.replace(IDENT_REGEX, (match) => {
125-
if (!data.has(match)) {
126-
return match;
127-
}
128-
129-
let request = urlToRequest(data.get(match), options.root);
130-
131-
if (options.interpolate === 'require') {
132-
request = data.get(match);
133-
}
134-
135-
return `" + __url__(require(${JSON.stringify(request)})) + "`;
136-
})};`;
124+
return `${importCode}${exportCode};`;
137125
}

src/utils.js

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { urlToRequest } from 'loader-utils';
2+
13
import parseAttributes from './parseAttributes';
4+
import { GET_URL_CODE, IDENT_REGEX } from './constants';
25

36
function randomIdent() {
47
return `xxxHTMLLINKxxx${Math.random()}${Math.random()}xxx`;
@@ -56,14 +59,6 @@ export function getUniqueIdent(data) {
5659
return ident;
5760
}
5861

59-
export function getExportsString(options) {
60-
if (options.esModule) {
61-
return 'export default ';
62-
}
63-
64-
return 'module.exports = ';
65-
}
66-
6762
export function replaceLinkWithIdent(source, link, ident, offset = 0) {
6863
return (
6964
source.substr(0, link.start + offset) +
@@ -75,3 +70,35 @@ export function replaceLinkWithIdent(source, link, ident, offset = 0) {
7570
export function isProductionMode(loaderContext) {
7671
return loaderContext.mode === 'production' || !loaderContext.mode;
7772
}
73+
74+
export function getImportCode(replacers) {
75+
if (replacers.size === 0) {
76+
return '';
77+
}
78+
79+
return GET_URL_CODE;
80+
}
81+
82+
export function getExportCode(content, replacers, options) {
83+
let newContent = content;
84+
85+
newContent = content.replace(IDENT_REGEX, (match) => {
86+
if (!replacers.has(match)) {
87+
return match;
88+
}
89+
90+
let request = urlToRequest(replacers.get(match), options.root);
91+
92+
if (options.interpolate === 'require') {
93+
request = replacers.get(match);
94+
}
95+
96+
return `" + __url__(require(${JSON.stringify(request)})) + "`;
97+
});
98+
99+
if (options.esModule) {
100+
return `export default ${newContent}`;
101+
}
102+
103+
return `module.exports = ${newContent}`;
104+
}

test/attributes-option.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ describe("'attributes' option", () => {
8484
);
8585
});
8686

87-
it('should work with a "boolean" notation', () => {
87+
it('should not handle attributes with a "boolean" notation equals "false"', () => {
8888
const result = loader.call(
8989
{
9090
mode: 'development',
@@ -94,11 +94,11 @@ describe("'attributes' option", () => {
9494
);
9595

9696
expect(result).toBe(
97-
`${GET_URL_CODE}module.exports = "Text <script src=\\"script.js\\"><img src=\\"image.png\\">";`
97+
'module.exports = "Text <script src=\\"script.js\\"><img src=\\"image.png\\">";'
9898
);
9999
});
100100

101-
it('should work with a "boolean" notation', () => {
101+
it('should handle attributes with a "boolean" notation equals "true"', () => {
102102
const result = loader.call(
103103
{
104104
mode: 'development',
@@ -130,7 +130,7 @@ describe("'attributes' option", () => {
130130
);
131131

132132
expect(result).toBe(
133-
`${GET_URL_CODE}module.exports = "<a href=\\"mailto:username@exampledomain.com\\"></a>";`
133+
'module.exports = "<a href=\\"mailto:username@exampledomain.com\\"></a>";'
134134
);
135135
});
136136
});

test/esModule-option.test.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import loader from '../src';
2-
import { GET_URL_CODE } from '../src/constants';
32

43
describe("'esModule' option", () => {
54
it('should use a CommonJS export by default', () => {
65
const result = loader.call({ query: '' }, '<p>Hello world!</p>');
76

8-
expect(result).toBe(
9-
`${GET_URL_CODE}module.exports = "<p>Hello world!</p>";`
10-
);
7+
expect(result).toBe(`module.exports = "<p>Hello world!</p>";`);
118
});
129

1310
it('should use a CommonJS export when the value is "false"', () => {
@@ -16,9 +13,7 @@ describe("'esModule' option", () => {
1613
'<p>Hello world!</p>'
1714
);
1815

19-
expect(result).toBe(
20-
`${GET_URL_CODE}module.exports = "<p>Hello world!</p>";`
21-
);
16+
expect(result).toBe(`module.exports = "<p>Hello world!</p>";`);
2217
});
2318

2419
it('should use an ES module export when the value is "true"', () => {
@@ -27,6 +22,6 @@ describe("'esModule' option", () => {
2722
'<p>Hello world!</p>'
2823
);
2924

30-
expect(result).toBe(`${GET_URL_CODE}export default "<p>Hello world!</p>";`);
25+
expect(result).toBe(`export default "<p>Hello world!</p>";`);
3126
});
3227
});

test/interpolate-option.test.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ describe("'interpolate' option", () => {
1010
);
1111

1212
expect(result).toBe(
13-
`${GET_URL_CODE}module.exports = "<img src=\\"\${\\"Hello \\" + (1+1)}\\">";`
13+
// eslint-disable-next-line no-template-curly-in-string
14+
'module.exports = "<img src=\\"${\\"Hello \\" + (1+1)}\\">";'
1415
);
1516
});
1617

@@ -26,7 +27,7 @@ describe("'interpolate' option", () => {
2627

2728
expect(result).toBe(
2829
// eslint-disable-next-line no-useless-escape
29-
`${GET_URL_CODE}module.exports = "<img src=\\"" + ("Hello " + (1 + 1)) + "\\"><img src=\\"" + ("Hello " + (1 + 1)) + "\\"><p>Something about the \` character</p><script>{\\\"json\\\": \\\"with \\\\\\\"quotes\\\\\\\" in value\\\"}</script>";`
30+
'module.exports = "<img src=\\"" + ("Hello " + (1 + 1)) + "\\"><img src=\\"" + ("Hello " + (1 + 1)) + "\\"><p>Something about the ` character</p><script>{\\"json\\": \\"with \\\\\\"quotes\\\\\\" in value\\"}</script>";'
3031
);
3132
});
3233

test/loader.test.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import loader from '../src';
2-
import { GET_URL_CODE } from '../src/constants';
32

43
describe('loader', () => {
54
it('should not make bad things with templates', () => {
@@ -9,7 +8,7 @@ describe('loader', () => {
98
);
109

1110
expect(result).toBe(
12-
`${GET_URL_CODE}module.exports = "<h3>#{number} {customer}</h3>\\n<p> {title} </p>";`
11+
'module.exports = "<h3>#{number} {customer}</h3>\\n<p> {title} </p>";'
1312
);
1413
});
1514

@@ -20,7 +19,7 @@ describe('loader', () => {
2019
);
2120

2221
expect(result).toBe(
23-
`${GET_URL_CODE}module.exports = "<script>{\\"json\\": \\"with \\\\\\"quotes\\\\\\" in value\\"}</script>";`
22+
'module.exports = "<script>{\\"json\\": \\"with \\\\\\"quotes\\\\\\" in value\\"}</script>";'
2423
);
2524
});
2625
});

test/minimize-option.test.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('"minimize" option', () => {
1313
);
1414

1515
expect(result).toBe(
16-
`${GET_URL_CODE}module.exports = "<!-- comment --><h1>My First Heading</h1>\\n\\n<p>My first paragraph.</p>";`
16+
'module.exports = "<!-- comment --><h1>My First Heading</h1>\\n\\n<p>My first paragraph.</p>";'
1717
);
1818
});
1919

@@ -27,7 +27,7 @@ describe('"minimize" option', () => {
2727
);
2828

2929
expect(result).toBe(
30-
`${GET_URL_CODE}module.exports = "<!-- comment --><h1>My First Heading</h1>\\n\\n<p>My first paragraph.</p>";`
30+
'module.exports = "<!-- comment --><h1>My First Heading</h1>\\n\\n<p>My first paragraph.</p>";'
3131
);
3232
});
3333

@@ -41,7 +41,7 @@ describe('"minimize" option', () => {
4141
);
4242

4343
expect(result).toBe(
44-
`${GET_URL_CODE}module.exports = "<h1>My First Heading</h1> <p>My first paragraph.</p>";`
44+
'module.exports = "<h1>My First Heading</h1> <p>My first paragraph.</p>";'
4545
);
4646
});
4747

@@ -71,7 +71,7 @@ describe('"minimize" option', () => {
7171
);
7272

7373
expect(result).toBe(
74-
`${GET_URL_CODE}module.exports = "<!-- comment --><h1>My First Heading</h1>\\n\\n<p>My first paragraph.</p>";`
74+
'module.exports = "<!-- comment --><h1>My First Heading</h1>\\n\\n<p>My first paragraph.</p>";'
7575
);
7676
});
7777

@@ -84,9 +84,7 @@ describe('"minimize" option', () => {
8484
'<input type="text" />'
8585
);
8686

87-
expect(result).toBe(
88-
`${GET_URL_CODE}module.exports = "<input type=text />";`
89-
);
87+
expect(result).toBe('module.exports = "<input type=text />";');
9088
});
9189

9290
it('should support options for minimizer', () => {
@@ -127,7 +125,7 @@ describe('"minimize" option', () => {
127125
);
128126

129127
expect(result).toBe(
130-
`${GET_URL_CODE}module.exports = "<h1>My First Heading</h1> <p>My first paragraph.</p> <script>console.log(\\"36\\")</script>";`
128+
'module.exports = "<h1>My First Heading</h1> <p>My first paragraph.</p> <script>console.log(\\"36\\")</script>";'
131129
);
132130
});
133131
});

test/root-options.test.js renamed to test/root-option.test.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ describe("'root' option", () => {
88
'Text <img src="/image.png">'
99
);
1010

11-
expect(result).toBe(
12-
`${GET_URL_CODE}module.exports = "Text <img src=\\"/image.png\\">";`
13-
);
11+
expect(result).toBe('module.exports = "Text <img src=\\"/image.png\\">";');
1412
});
1513

1614
it('should work', () => {

0 commit comments

Comments
 (0)