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

feat: supported supports() and layer() in @import at-rule #1377

Merged
merged 37 commits into from Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d3df855
feat: supported `supports()` and `layer()` in `@import` at-rule
alexander-akait Sep 15, 2021
e645c1a
test: update
alexander-akait Sep 15, 2021
23e819d
test: more
alexander-akait Sep 15, 2021
837f313
test: more
alexander-akait Sep 15, 2021
4ed5f9a
test: fix
alexander-akait Sep 16, 2021
aafa0d8
test: more
alexander-akait Sep 16, 2021
803aa9c
test: more
alexander-akait Sep 16, 2021
f5097f1
fix: runtime
alexander-akait Sep 16, 2021
3748511
test: fix
alexander-akait Sep 16, 2021
1292f23
fix: merging `supports`
alexander-akait Sep 16, 2021
f44ab0e
test: update
alexander-akait Sep 16, 2021
0b9e498
test: more
alexander-akait Sep 16, 2021
e184446
test: more
alexander-akait Sep 16, 2021
d80e2c3
feat: filter supports `supports` and `layer`
alexander-akait Sep 16, 2021
4cb374f
test: more
alexander-akait Sep 16, 2021
0ccbff0
test: more
alexander-akait Sep 16, 2021
738e940
fix: api
alexander-akait Sep 16, 2021
d485766
test: more
alexander-akait Sep 16, 2021
8368cb5
fix: merge `@media`
alexander-akait Sep 16, 2021
8cf1fc0
test: more
alexander-akait Sep 16, 2021
ce6ee30
test: more
alexander-akait Sep 16, 2021
d1c2084
test: more
alexander-akait Sep 16, 2021
557414c
test: more
alexander-akait Sep 16, 2021
2f1b66b
test: more
alexander-akait Sep 16, 2021
b1a9397
test: more
alexander-akait Sep 16, 2021
ac2f5dd
test: more
alexander-akait Sep 16, 2021
792ad9f
test: more
alexander-akait Sep 16, 2021
b3efd27
test: more
alexander-akait Sep 16, 2021
94a4313
test: more
alexander-akait Sep 16, 2021
95f3eb6
fix: merging `@layer`
alexander-akait Sep 16, 2021
5563276
test: update
alexander-akait Sep 16, 2021
ade4d84
fix: order
alexander-akait Sep 16, 2021
176383f
fix: reduce runtime
alexander-akait Sep 17, 2021
87c5031
fix: reduce runtime
alexander-akait Sep 17, 2021
b770635
fix: reduce runtime
alexander-akait Sep 17, 2021
8b3fc11
fix: source maps
alexander-akait Sep 17, 2021
f08ee98
test: more
alexander-akait Sep 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -12,6 +12,7 @@ module.exports = {
"no-param-reassign": "off",
"no-continue": "off",
"no-underscore-dangle": "off",
"no-undefined": "off",
},
},
],
Expand Down
6 changes: 2 additions & 4 deletions src/index.js
Expand Up @@ -71,7 +71,7 @@ export default async function loader(content, map, meta) {
context: this.context,
rootContext: this.rootContext,
resourcePath: this.resourcePath,
filter: getFilter(options.import.filter, this.resourcePath),
filter: options.import.filter,
resolver,
urlHandler: (url) =>
stringifyRequest(
Expand Down Expand Up @@ -205,13 +205,11 @@ export default async function loader(content, map, meta) {

if (options.sourceMap) {
imports.unshift({
type: "api_sourcemap_import",
importName: "___CSS_LOADER_API_SOURCEMAP_IMPORT___",
url: stringifyRequest(this, require.resolve("./runtime/noSourceMaps")),
url: stringifyRequest(this, require.resolve("./runtime/sourceMaps")),
});
} else {
imports.unshift({
type: "api_sourcemap_import",
importName: "___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___",
url: stringifyRequest(this, require.resolve("./runtime/noSourceMaps")),
});
Expand Down
84 changes: 72 additions & 12 deletions src/plugins/postcss-import-parser.js
Expand Up @@ -118,15 +118,54 @@ function parseNode(atRule, key) {
throw error;
}

const mediaNodes = paramsNodes.slice(1);
const additionalNodes = paramsNodes.slice(1);

let supports;
let layer;
let media;

if (mediaNodes.length > 0) {
media = valueParser.stringify(mediaNodes).trim().toLowerCase();
if (additionalNodes.length > 0) {
let nodes = [];

for (const node of additionalNodes) {
nodes.push(node);

const isLayerFunction =
node.type === "function" && node.value.toLowerCase() === "layer";
const isLayerWord =
node.type === "word" && node.value.toLowerCase() === "layer";

if (isLayerFunction || isLayerWord) {
if (isLayerFunction) {
nodes.splice(nodes.length - 1, 1, ...node.nodes);
} else {
nodes.splice(nodes.length - 1, 1, {
type: "string",
value: "",
unclosed: false,
});
}

layer = valueParser.stringify(nodes).trim().toLowerCase();
nodes = [];
} else if (
node.type === "function" &&
node.value.toLowerCase() === "supports"
) {
nodes.splice(nodes.length - 1, 1, ...node.nodes);

supports = valueParser.stringify(nodes).trim().toLowerCase();
nodes = [];
}
}

if (nodes.length > 0) {
media = valueParser.stringify(nodes).trim().toLowerCase();
}
}

// eslint-disable-next-line consistent-return
return { atRule, prefix, url, media, isRequestable };
return { atRule, prefix, url, layer, supports, media, isRequestable };
}

const plugin = (options = {}) => {
Expand Down Expand Up @@ -160,11 +199,24 @@ const plugin = (options = {}) => {

const resolvedAtRules = await Promise.all(
parsedAtRules.map(async (parsedAtRule) => {
const { atRule, isRequestable, prefix, url, media } =
parsedAtRule;
const {
atRule,
isRequestable,
prefix,
url,
layer,
supports,
media,
} = parsedAtRule;

if (options.filter) {
const needKeep = await options.filter(url, media);
const needKeep = await options.filter(
url,
media,
options.resourcePath,
supports,
layer
);

if (!needKeep) {
return;
Expand Down Expand Up @@ -192,13 +244,20 @@ const plugin = (options = {}) => {
atRule.remove();

// eslint-disable-next-line consistent-return
return { url: resolvedUrl, media, prefix, isRequestable };
return {
url: resolvedUrl,
layer,
supports,
media,
prefix,
isRequestable,
};
}

atRule.remove();

// eslint-disable-next-line consistent-return
return { url, media, prefix, isRequestable };
return { url, layer, supports, media, prefix, isRequestable };
})
);

Expand All @@ -212,10 +271,11 @@ const plugin = (options = {}) => {
continue;
}

const { url, isRequestable, media } = resolvedAtRule;
const { url, isRequestable, layer, supports, media } =
resolvedAtRule;

if (!isRequestable) {
options.api.push({ url, media, index });
options.api.push({ url, layer, supports, media, index });

// eslint-disable-next-line no-continue
continue;
Expand All @@ -237,7 +297,7 @@ const plugin = (options = {}) => {
});
}

options.api.push({ importName, media, index });
options.api.push({ importName, layer, supports, media, index });
}
},
};
Expand Down
59 changes: 52 additions & 7 deletions src/runtime/api.js
Expand Up @@ -8,20 +8,44 @@ module.exports = (cssWithMappingToString) => {
// return the list of modules as css string
list.toString = function toString() {
return this.map((item) => {
const content = cssWithMappingToString(item);
let content = "";

const needLayer = typeof item[5] !== "undefined";

if (item[4]) {
content += `@supports (${item[4]}) {`;
}

if (item[2]) {
content += `@media ${item[2]} {`;
}

if (needLayer) {
content += `@layer${item[5].length > 0 ? ` ${item[5]}` : ""} {`;
}

content += cssWithMappingToString(item);

if (needLayer) {
content += "}";
}

if (item[2]) {
return `@media ${item[2]} {${content}}`;
content += "}";
}

if (item[4]) {
content += "}";
}

return content;
}).join("");
};

// import a list of modules into the list
list.i = function i(modules, mediaQuery, dedupe) {
list.i = function i(modules, media, dedupe, supports, layer) {
if (typeof modules === "string") {
modules = [[null, modules, ""]];
modules = [[null, modules, undefined]];
}

const alreadyImportedModules = {};
Expand All @@ -43,11 +67,32 @@ module.exports = (cssWithMappingToString) => {
continue;
}

if (mediaQuery) {
if (typeof layer !== "undefined") {
if (typeof item[5] === "undefined") {
item[5] = layer;
} else {
item[1] = `@layer${item[5].length > 0 ? ` ${item[5]}` : ""} {${
item[1]
}}`;
item[5] = layer;
}
}

if (media) {
if (!item[2]) {
item[2] = mediaQuery;
item[2] = media;
} else {
item[1] = `@media ${item[2]} {${item[1]}}`;
item[2] = media;
}
}

if (supports) {
if (!item[4]) {
item[4] = `${supports}`;
} else {
item[2] = `${mediaQuery} and ${item[2]}`;
item[1] = `@supports (${item[4]}) {${item[1]}}`;
item[4] = supports;
}
}

Expand Down
60 changes: 51 additions & 9 deletions src/utils.js
Expand Up @@ -921,6 +921,34 @@ function normalizeSourceMapForRuntime(map, loaderContext) {
return JSON.stringify(resultMap);
}

function printParams(media, dedupe, supports, layer) {
let result = "";

if (typeof layer !== "undefined") {
result = `, ${JSON.stringify(layer)}`;
}

if (typeof supports !== "undefined") {
result = `, ${JSON.stringify(supports)}${result}`;
} else if (result.length > 0) {
result = `, undefined${result}`;
}

if (dedupe) {
result = `, true${result}`;
} else if (result.length > 0) {
result = `, false${result}`;
}

if (media) {
result = `${JSON.stringify(media)}${result}`;
} else if (result.length > 0) {
result = `""${result}`;
}

return result;
}

function getModuleCode(result, api, replacements, options, loaderContext) {
if (options.modules.exportOnlyLocals === true) {
return "";
Expand All @@ -939,15 +967,22 @@ function getModuleCode(result, api, replacements, options, loaderContext) {
});\n`;

for (const item of api) {
const { url, media, dedupe } = item;

beforeCode += url
? `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(
`@import url(${url});`
)}${media ? `, ${JSON.stringify(media)}` : ""}]);\n`
: `___CSS_LOADER_EXPORT___.i(${item.importName}${
media ? `, ${JSON.stringify(media)}` : dedupe ? ', ""' : ""
}${dedupe ? ", true" : ""});\n`;
const { url, layer, supports, media, dedupe } = item;

if (url) {
// eslint-disable-next-line no-undefined
const printedParam = printParams(media, undefined, supports, layer);

beforeCode += `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(
`@import url(${url});`
)}${printedParam.length > 0 ? `, ${printedParam}` : ""}]);\n`;
} else {
const printedParam = printParams(media, dedupe, supports, layer);

beforeCode += `___CSS_LOADER_EXPORT___.i(${item.importName}${
printedParam.length > 0 ? `, ${printedParam}` : ""
});\n`;
}
}

for (const item of replacements) {
Expand Down Expand Up @@ -980,6 +1015,13 @@ function getModuleCode(result, api, replacements, options, loaderContext) {
}
}

// Indexes description:
// 0 - module id
// 1 - CSS code
// 2 - media
// 3 - source map
// 4 - supports
// 5 - layer
return `${beforeCode}// Module\n___CSS_LOADER_EXPORT___.push([module.id, ${code}, ""${sourceMapValue}]);\n`;
}

Expand Down