Skip to content

Commit

Permalink
feat: respected the style field from package.json (#1099)
Browse files Browse the repository at this point in the history
  • Loading branch information
cap-Bernardito authored Jul 7, 2020
1 parent fcdc1ab commit edf5347
Show file tree
Hide file tree
Showing 24 changed files with 1,492 additions and 1,148 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ Thumbs.db
.vscode
*.sublime-project
*.sublime-workspace
/test/fixtures/import/import-absolute.css
1,994 changes: 958 additions & 1,036 deletions package-lock.json

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,20 @@ export default function loader(content, map, meta) {
plugins.push(icssParser({ urlHandler }));

if (options.import !== false && exportType === 'full') {
const resolver = this.getResolve({
mainFields: ['css', 'style', 'main', '...'],
mainFiles: ['index', '...'],
extensions: ['.css'],
restrictions: [/\.css$/i],
conditionNames: ['style'],
});

plugins.push(
importParser({
context: this.context,
rootContext: this.rootContext,
filter: getFilter(options.import, this.resourcePath),
resolver,
urlHandler,
})
);
Expand Down Expand Up @@ -125,6 +136,24 @@ export default function loader(content, map, meta) {
}
}

apiImports.sort((a, b) => a.index - b.index);

/*
* Order
* CSS_LOADER_ICSS_IMPORT: [],
* CSS_LOADER_AT_RULE_IMPORT: [],
* CSS_LOADER_GET_URL_IMPORT: [],
* CSS_LOADER_URL_IMPORT: [],
* CSS_LOADER_URL_REPLACEMENT: [],
* */

imports.sort((a, b) => {
return (
(b.order < a.order) - (a.order < b.order) ||
(b.index < a.index) - (a.index < b.index)
);
});

const { localsConvention } = options;
const esModule =
typeof options.esModule !== 'undefined' ? options.esModule : false;
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/postcss-icss-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export default postcss.plugin(
{
type: 'import',
value: {
// 'CSS_LOADER_ICSS_IMPORT'
order: 0,
importName,
url: options.urlHandler ? options.urlHandler(url) : url,
},
Expand Down
235 changes: 139 additions & 96 deletions src/plugins/postcss-import-parser.js
Original file line number Diff line number Diff line change
@@ -1,132 +1,175 @@
import postcss from 'postcss';
import valueParser from 'postcss-value-parser';
import { isUrlRequest } from 'loader-utils';

import { normalizeUrl } from '../utils';
import { normalizeUrl, resolveRequests, isUrlRequestable } from '../utils';

const pluginName = 'postcss-import-parser';

export default postcss.plugin(pluginName, (options) => (css, result) => {
const importsMap = new Map();

css.walkAtRules(/^import$/i, (atRule) => {
// Convert only top-level @import
if (atRule.parent.type !== 'root') {
return;
}

// Nodes do not exists - `@import url('http://') :root {}`
if (atRule.nodes) {
result.warn(
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it.",
{ node: atRule }
);
return new Promise((resolve, reject) => {
const importsMap = new Map();
const tasks = [];

return;
}

const { nodes } = valueParser(atRule.params);

// No nodes - `@import ;`
// Invalid type - `@import foo-bar;`
if (
nodes.length === 0 ||
(nodes[0].type !== 'string' && nodes[0].type !== 'function')
) {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});

return;
}

let isStringValue;
let url;

if (nodes[0].type === 'string') {
isStringValue = true;
url = nodes[0].value;
} else if (nodes[0].type === 'function') {
// Invalid function - `@import nourl(test.css);`
if (nodes[0].value.toLowerCase() !== 'url') {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});
// A counter is used instead of an index in callback css.walkAtRules because we mutate AST (atRule.remove())
let index = 0;

css.walkAtRules(/^import$/i, (atRule) => {
// Convert only top-level @import
if (atRule.parent.type !== 'root') {
return;
}

isStringValue =
nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
url = isStringValue
? nodes[0].nodes[0].value
: valueParser.stringify(nodes[0].nodes);
}
// Nodes do not exists - `@import url('http://') :root {}`
if (atRule.nodes) {
result.warn(
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it.",
{ node: atRule }
);

// Empty url - `@import "";` or `@import url();`
if (url.trim().length === 0) {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});
return;
}

return;
}
const { nodes } = valueParser(atRule.params);

const isRequestable = isUrlRequest(url);
// No nodes - `@import ;`
// Invalid type - `@import foo-bar;`
if (
nodes.length === 0 ||
(nodes[0].type !== 'string' && nodes[0].type !== 'function')
) {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});

if (isRequestable) {
url = normalizeUrl(url, isStringValue);
return;
}

let isStringValue;
let url;

if (nodes[0].type === 'string') {
isStringValue = true;
url = nodes[0].value;
} else if (nodes[0].type === 'function') {
// Invalid function - `@import nourl(test.css);`
if (nodes[0].value.toLowerCase() !== 'url') {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});

return;
}

isStringValue =
nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
url = isStringValue
? nodes[0].nodes[0].value
: valueParser.stringify(nodes[0].nodes);
}

// Empty url after normalize - `@import '\
// \
// \
// ';
// Empty url - `@import "";` or `@import url();`
if (url.trim().length === 0) {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});

return;
}
}

const media = valueParser.stringify(nodes.slice(1)).trim().toLowerCase();
let normalizedUrl;

if (options.filter && !options.filter({ url, media })) {
return;
}
const isRequestable = isUrlRequestable(url);

atRule.remove();
if (isRequestable) {
normalizedUrl = normalizeUrl(url, isStringValue, options.rootContext);

if (isRequestable) {
const importKey = url;
let importName = importsMap.get(importKey);
// Empty url after normalize - `@import '\
// \
// \
// ';
if (normalizedUrl.trim().length === 0) {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule,
});

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

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

result.messages.push({
type: 'api-import',
value: { type: 'internal', importName, media },
});
const media = valueParser.stringify(nodes.slice(1)).trim().toLowerCase();

return;
}
if (
options.filter &&
!options.filter({ url: normalizedUrl || url, media })
) {
return;
}

result.messages.push({
pluginName,
type: 'api-import',
value: { type: 'external', url, media },
atRule.remove();

index += 1;

tasks.push(
Promise.resolve(index).then(async (currentIndex) => {
if (isRequestable) {
const importKey = normalizedUrl;
let importName = importsMap.get(importKey);

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

const { resolver, context } = options;

let resolvedUrl;

try {
resolvedUrl = await resolveRequests(resolver, context, [
...new Set([normalizedUrl, url]),
]);
} catch (error) {
throw error;
}

result.messages.push({
type: 'import',
value: {
// 'CSS_LOADER_AT_RULE_IMPORT'
order: 1,
importName,
url: options.urlHandler
? options.urlHandler(resolvedUrl)
: resolvedUrl,
index: currentIndex,
},
});
}

result.messages.push({
type: 'api-import',
value: {
type: 'internal',
importName,
media,
index: currentIndex,
},
});

return;
}

result.messages.push({
pluginName,
type: 'api-import',
value: { type: 'external', url, media, index: currentIndex },
});
})
);
});

Promise.all(tasks).then(
() => resolve(),
(error) => reject(error)
);
});
});
20 changes: 19 additions & 1 deletion src/plugins/postcss-url-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {

let hasHelper = false;

let index = 0;

css.walkDecls((decl) => {
if (!needParseDecl.test(decl.value)) {
return;
Expand Down Expand Up @@ -99,6 +101,8 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
const importKey = normalizedUrl;
let importName = importsMap.get(importKey);

index += 1;

if (!importName) {
importName = `___CSS_LOADER_URL_IMPORT_${importsMap.size}___`;
importsMap.set(importKey, importName);
Expand All @@ -110,10 +114,13 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
pluginName,
type: 'import',
value: {
// 'CSS_LOADER_GET_URL_IMPORT'
order: 2,
importName: '___CSS_LOADER_GET_URL_IMPORT___',
url: options.urlHandler
? options.urlHandler(urlToHelper)
: urlToHelper,
index,
},
});

Expand All @@ -124,10 +131,13 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
pluginName,
type: 'import',
value: {
// 'CSS_LOADER_URL_IMPORT'
order: 3,
importName,
url: options.urlHandler
? options.urlHandler(normalizedUrl)
: normalizedUrl,
index,
},
});
}
Expand All @@ -142,7 +152,15 @@ export default postcss.plugin(pluginName, (options) => (css, result) => {
result.messages.push({
pluginName,
type: 'url-replacement',
value: { replacementName, importName, hash, needQuotes },
value: {
// 'CSS_LOADER_URL_REPLACEMENT'
order: 4,
replacementName,
importName,
hash,
needQuotes,
index,
},
});
}

Expand Down
Loading

0 comments on commit edf5347

Please sign in to comment.