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

refactor: code #1059

Merged
merged 13 commits into from Mar 25, 2020
27 changes: 12 additions & 15 deletions src/index.js
Expand Up @@ -2,7 +2,7 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
import { getOptions, isUrlRequest } from 'loader-utils';
import { getOptions, isUrlRequest, stringifyRequest } from 'loader-utils';
import postcss from 'postcss';
import postcssPkg from 'postcss/package.json';
import validateOptions from 'schema-utils';
Expand All @@ -13,6 +13,7 @@ import Warning from './Warning';
import schema from './options.json';
import { icssParser, importParser, urlParser } from './plugins';
import {
getPreRequester,
getExportCode,
getFilter,
getImportCode,
Expand All @@ -38,13 +39,17 @@ export default function loader(content, map, meta) {
}

const exportType = options.onlyLocals ? 'locals' : 'full';
const preRequester = getPreRequester(this);
const urlHandler = (url) =>
stringifyRequest(this, preRequester(options.importLoaders) + url);

plugins.push(icssParser());
plugins.push(icssParser({ urlHandler }));

if (options.import !== false && exportType === 'full') {
plugins.push(
importParser({
filter: getFilter(options.import, this.resourcePath),
urlHandler,
})
);
}
Expand All @@ -55,6 +60,7 @@ export default function loader(content, map, meta) {
filter: getFilter(options.url, this.resourcePath, (value) =>
isUrlRequest(value)
),
urlHandler: (url) => stringifyRequest(this, url),
})
);
}
Expand Down Expand Up @@ -118,30 +124,21 @@ export default function loader(content, map, meta) {
}
}

const { importLoaders, localsConvention } = options;
const { localsConvention } = options;
const esModule =
typeof options.esModule !== 'undefined' ? options.esModule : false;

const importCode = getImportCode(
this,
imports,
exportType,
importLoaders,
esModule
);
const importCode = getImportCode(this, exportType, imports, esModule);
const moduleCode = getModuleCode(
this,
result,
exportType,
esModule,
sourceMap,
importLoaders,
apiImports,
urlReplacements,
icssReplacements
icssReplacements,
esModule
);
const exportCode = getExportCode(
this,
exports,
exportType,
localsConvention,
Expand Down
2 changes: 1 addition & 1 deletion src/options.json
Expand Up @@ -83,7 +83,7 @@
"type": "boolean"
},
{
"type": "number"
"type": "integer"
}
]
},
Expand Down
86 changes: 46 additions & 40 deletions src/plugins/postcss-icss-parser.js
Expand Up @@ -28,50 +28,56 @@ function makeRequestableIcssImports(icssImports) {
}, {});
}

export default postcss.plugin('postcss-icss-parser', () => (css, result) => {
const importReplacements = Object.create(null);
const extractedICSS = extractICSS(css);
const icssImports = makeRequestableIcssImports(extractedICSS.icssImports);

for (const [importIndex, url] of Object.keys(icssImports).entries()) {
const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;

result.messages.push(
{
type: 'import',
value: { type: 'icss', importName, url },
},
{
type: 'api-import',
value: { type: 'internal', importName, dedupe: true },
export default postcss.plugin(
'postcss-icss-parser',
(options) => (css, result) => {
const importReplacements = Object.create(null);
const extractedICSS = extractICSS(css);
const icssImports = makeRequestableIcssImports(extractedICSS.icssImports);

for (const [importIndex, url] of Object.keys(icssImports).entries()) {
const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;

result.messages.push(
{
type: 'import',
value: {
importName,
url: options.urlHandler ? options.urlHandler(url) : url,
},
},
{
type: 'api-import',
value: { type: 'internal', importName, dedupe: true },
}
);

const tokenMap = icssImports[url];
const tokens = Object.keys(tokenMap);

for (const [replacementIndex, token] of tokens.entries()) {
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
const localName = tokenMap[token];

importReplacements[token] = replacementName;

result.messages.push({
type: 'icss-replacement',
value: { replacementName, importName, localName },
});
}
);

const tokenMap = icssImports[url];
const tokens = Object.keys(tokenMap);

for (const [replacementIndex, token] of tokens.entries()) {
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
const localName = tokenMap[token];

importReplacements[token] = replacementName;

result.messages.push({
type: 'icss-replacement',
value: { replacementName, importName, localName },
});
}
}

if (Object.keys(importReplacements).length > 0) {
replaceSymbols(css, importReplacements);
}
if (Object.keys(importReplacements).length > 0) {
replaceSymbols(css, importReplacements);
}

const { icssExports } = extractedICSS;
const { icssExports } = extractedICSS;

for (const name of Object.keys(icssExports)) {
const value = replaceValueSymbols(icssExports[name], importReplacements);
for (const name of Object.keys(icssExports)) {
const value = replaceValueSymbols(icssExports[name], importReplacements);

result.messages.push({ type: 'export', value: { name, value } });
result.messages.push({ type: 'export', value: { name, value } });
}
}
});
);
5 changes: 4 additions & 1 deletion src/plugins/postcss-import-parser.js
Expand Up @@ -108,7 +108,10 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {

result.messages.push({
type: 'import',
value: { type: '@import', importName, url },
value: {
importName,
url: options.urlHandler ? options.urlHandler(url) : url,
},
});
}

Expand Down
15 changes: 10 additions & 5 deletions src/plugins/postcss-url-parser.js
Expand Up @@ -73,7 +73,8 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
const parsed = valueParser(decl.value);

walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
if (url.trim().replace(/\\[\r\n]/g, '').length === 0) {
// https://www.w3.org/TR/css-syntax-3/#typedef-url-token
if (url.replace(/^[\s]+|[\s]+$/g, '').length === 0) {
result.warn(
`Unable to find uri in '${decl ? decl.toString() : decl.value}'`,
{ node: decl }
Expand Down Expand Up @@ -103,13 +104,16 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
importsMap.set(importKey, importName);

if (!hasHelper) {
const urlToHelper = require.resolve('../runtime/getUrl.js');

result.messages.push({
pluginName,
type: 'import',
value: {
type: 'url',
importName: '___CSS_LOADER_GET_URL_IMPORT___',
url: require.resolve('../runtime/getUrl.js'),
url: options.urlHandler
? options.urlHandler(urlToHelper)
: urlToHelper,
},
});

Expand All @@ -120,9 +124,10 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
pluginName,
type: 'import',
value: {
type: 'url',
importName,
url: normalizedUrl,
url: options.urlHandler
? options.urlHandler(normalizedUrl)
: normalizedUrl,
},
});
}
Expand Down
62 changes: 29 additions & 33 deletions src/utils.js
Expand Up @@ -178,30 +178,34 @@ function normalizeSourceMap(map) {
return newMap;
}

function getImportPrefix(loaderContext, importLoaders) {
if (importLoaders === false) {
return '';
}
function getPreRequester(loaderContext) {
const { loaders, loaderIndex } = loaderContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function getPreRequester(loaderContext) {
const { loaders, loaderIndex } = loaderContext;
function getPreRequester({ loaders, loaderIndex }) {

const cache = Object.create(null);

const numberImportedLoaders = parseInt(importLoaders, 10) || 0;
const loadersRequest = loaderContext.loaders
.slice(
loaderContext.loaderIndex,
loaderContext.loaderIndex + 1 + numberImportedLoaders
)
.map((x) => x.request)
.join('!');
return (number) => {
if (cache[number]) {
return cache[number];
}

return `-!${loadersRequest}!`;
if (number === false) {
cache[number] = '';
} else {
const loadersRequest = loaders
.slice(
loaderIndex,
loaderIndex + 1 + (typeof number !== 'number' ? 0 : number)
)
.map((x) => x.request)
.join('!');

cache[number] = `-!${loadersRequest}!`;
}

return cache[number];
};
}

function getImportCode(
loaderContext,
imports,
exportType,
importLoaders,
esModule
) {
function getImportCode(loaderContext, exportType, imports, esModule) {
let code = '';

if (exportType === 'full') {
Expand All @@ -217,31 +221,23 @@ function getImportCode(

for (const item of imports) {
const { importName, url } = item;
const importUrl = stringifyRequest(
loaderContext,
item.type !== 'url'
? getImportPrefix(loaderContext, importLoaders) + url
: url
);

code += esModule
? `import ${importName} from ${importUrl};\n`
: `var ${importName} = require(${importUrl});\n`;
? `import ${importName} from ${url};\n`
: `var ${importName} = require(${url});\n`;
}

return code ? `// Imports\n${code}` : '';
}

function getModuleCode(
loaderContext,
result,
exportType,
esModule,
sourceMap,
importLoaders,
apiImports,
urlReplacements,
icssReplacements
icssReplacements,
esModule
) {
if (exportType !== 'full') {
return '';
Expand Down Expand Up @@ -306,7 +302,6 @@ function dashesCamelCase(str) {
}

function getExportCode(
loaderContext,
exports,
exportType,
localsConvention,
Expand Down Expand Up @@ -393,6 +388,7 @@ export {
getFilter,
getModulesPlugins,
normalizeSourceMap,
getPreRequester,
getImportCode,
getModuleCode,
getExportCode,
Expand Down