Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@linaria/server

Package Overview
Dependencies
Maintainers
4
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@linaria/server - npm Package Compare versions

Comparing version 4.0.0 to 4.1.0

75

esm/collect.js

@@ -0,24 +1,36 @@

import postcss from 'postcss';
/**
* This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments
* Used to escape `RegExp`
* [syntax characters](https://262.ecma-international.org/7.0/#sec-regular-expressions-patterns).
*/
import postcss from 'postcss';
const extractClassesFromHtml = html => {
function escapeRegex(string) {
return string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
}
const extractClassesFromHtml = (html, ignoredClasses) => {
const htmlClasses = [];
const regex = /\s+class="([^"]+)"/gm;
let match = regex.exec(html);
const ignoredClassesDeduped = new Set(ignoredClasses);
while (match !== null) {
match[1].split(' ').forEach(className => {
// eslint-disable-next-line no-param-reassign
className = className.replace(/\\|\^|\$|\{|\}|\[|\]|\(|\)|\.|\*|\+|\?|\|/g, '\\$&');
htmlClasses.push(className);
className = escapeRegex(className);
if (className !== '' && !ignoredClassesDeduped.has(className)) {
htmlClasses.push(className);
}
});
match = regex.exec(html);
}
return new RegExp(htmlClasses.join('|'), 'gm');
};
export default function collect(html, css) {
/**
* This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments
* @param {string} html the HTML from which classes will be parsed
* @param {string} css the CSS file from which selectors will be parsed and determined as critical or other
* @param {string[]} ignoredClasses classes that, when present in the HTML, will not be included in the regular expression used to match selectors
* @param {string[]} blockedClasses classes that, when contained in a selector, will cause the selector to be marked as not critical
* @returns {CollectResult} object containing the critical and other CSS styles
*/
export default function collect(html, css, classnameModifiers) {
const animations = new Set();

@@ -28,33 +40,39 @@ const other = postcss.root();

const stylesheet = postcss.parse(css);
const htmlClassesRegExp = extractClassesFromHtml(html);
const ignoredClasses = classnameModifiers?.ignoredClasses ?? [];
const blockedClasses = classnameModifiers?.blockedClasses ?? [];
const htmlClassesRegExp = extractClassesFromHtml(html, ignoredClasses);
const blockedClassesSanitized = blockedClasses.map(escapeRegex);
const blockedClassesRegExp = new RegExp(blockedClassesSanitized.join('|'), 'gm');
const isCritical = rule => {
// Only check class names selectors
if ('selector' in rule && rule.selector.startsWith('.')) {
const isExcluded = blockedClasses.length > 0 && blockedClassesRegExp.test(rule.selector);
if (isExcluded) return false;
return Boolean(rule.selector.match(htmlClassesRegExp));
}
return true;
};
const handleAtRule = rule => {
let addedToCritical = false;
rule.each(childRule => {
if (isCritical(childRule) && !addedToCritical) {
critical.append(rule.clone());
addedToCritical = true;
}
});
if (rule.name === 'keyframes') {
return;
}
if (addedToCritical) {
rule.remove();
} else {
other.append(rule);
const criticalRule = rule.clone();
const otherRule = rule.clone();
let removedNodesFromOther = 0;
criticalRule.each((childRule, index) => {
if (isCritical(childRule)) {
otherRule.nodes[index - removedNodesFromOther]?.remove();
removedNodesFromOther += 1;
} else {
childRule.remove();
}
});
rule.remove();
if (criticalRule.nodes.length > 0) {
critical.append(criticalRule);
}
if (otherRule.nodes.length > 0) {
other.append(otherRule);
}
};
stylesheet.walkAtRules('font-face', rule => {

@@ -74,3 +92,2 @@ /**

}
if (rule.parent?.type === 'atrule') {

@@ -81,6 +98,4 @@ if (!walkedAtRules.has(rule.parent)) {

}
return;
}
if (isCritical(rule)) {

@@ -87,0 +102,0 @@ critical.append(rule);

83

lib/collect.js

@@ -7,70 +7,83 @@ "use strict";

exports.default = collect;
var _postcss = _interopRequireDefault(require("postcss"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments
* Used to escape `RegExp`
* [syntax characters](https://262.ecma-international.org/7.0/#sec-regular-expressions-patterns).
*/
const extractClassesFromHtml = html => {
function escapeRegex(string) {
return string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
}
const extractClassesFromHtml = (html, ignoredClasses) => {
const htmlClasses = [];
const regex = /\s+class="([^"]+)"/gm;
let match = regex.exec(html);
const ignoredClassesDeduped = new Set(ignoredClasses);
while (match !== null) {
match[1].split(' ').forEach(className => {
// eslint-disable-next-line no-param-reassign
className = className.replace(/\\|\^|\$|\{|\}|\[|\]|\(|\)|\.|\*|\+|\?|\|/g, '\\$&');
htmlClasses.push(className);
className = escapeRegex(className);
if (className !== '' && !ignoredClassesDeduped.has(className)) {
htmlClasses.push(className);
}
});
match = regex.exec(html);
}
return new RegExp(htmlClasses.join('|'), 'gm');
};
function collect(html, css) {
/**
* This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments
* @param {string} html the HTML from which classes will be parsed
* @param {string} css the CSS file from which selectors will be parsed and determined as critical or other
* @param {string[]} ignoredClasses classes that, when present in the HTML, will not be included in the regular expression used to match selectors
* @param {string[]} blockedClasses classes that, when contained in a selector, will cause the selector to be marked as not critical
* @returns {CollectResult} object containing the critical and other CSS styles
*/
function collect(html, css, classnameModifiers) {
var _classnameModifiers$i, _classnameModifiers$b;
const animations = new Set();
const other = _postcss.default.root();
const critical = _postcss.default.root();
const stylesheet = _postcss.default.parse(css);
const htmlClassesRegExp = extractClassesFromHtml(html);
const ignoredClasses = (_classnameModifiers$i = classnameModifiers === null || classnameModifiers === void 0 ? void 0 : classnameModifiers.ignoredClasses) !== null && _classnameModifiers$i !== void 0 ? _classnameModifiers$i : [];
const blockedClasses = (_classnameModifiers$b = classnameModifiers === null || classnameModifiers === void 0 ? void 0 : classnameModifiers.blockedClasses) !== null && _classnameModifiers$b !== void 0 ? _classnameModifiers$b : [];
const htmlClassesRegExp = extractClassesFromHtml(html, ignoredClasses);
const blockedClassesSanitized = blockedClasses.map(escapeRegex);
const blockedClassesRegExp = new RegExp(blockedClassesSanitized.join('|'), 'gm');
const isCritical = rule => {
// Only check class names selectors
if ('selector' in rule && rule.selector.startsWith('.')) {
const isExcluded = blockedClasses.length > 0 && blockedClassesRegExp.test(rule.selector);
if (isExcluded) return false;
return Boolean(rule.selector.match(htmlClassesRegExp));
}
return true;
};
const handleAtRule = rule => {
let addedToCritical = false;
rule.each(childRule => {
if (isCritical(childRule) && !addedToCritical) {
critical.append(rule.clone());
addedToCritical = true;
}
});
if (rule.name === 'keyframes') {
return;
}
if (addedToCritical) {
rule.remove();
} else {
other.append(rule);
const criticalRule = rule.clone();
const otherRule = rule.clone();
let removedNodesFromOther = 0;
criticalRule.each((childRule, index) => {
if (isCritical(childRule)) {
var _otherRule$nodes;
(_otherRule$nodes = otherRule.nodes[index - removedNodesFromOther]) === null || _otherRule$nodes === void 0 ? void 0 : _otherRule$nodes.remove();
removedNodesFromOther += 1;
} else {
childRule.remove();
}
});
rule.remove();
if (criticalRule.nodes.length > 0) {
critical.append(criticalRule);
}
if (otherRule.nodes.length > 0) {
other.append(otherRule);
}
};
stylesheet.walkAtRules('font-face', rule => {
var _rule$parent;
/**

@@ -87,7 +100,5 @@ * @font-face rules may be defined also in CSS conditional groups (eg. @media)

var _rule$parent2;
if (rule.parent && 'name' in rule.parent && rule.parent.name === 'keyframes') {
return;
}
if (((_rule$parent2 = rule.parent) === null || _rule$parent2 === void 0 ? void 0 : _rule$parent2.type) === 'atrule') {

@@ -98,6 +109,4 @@ if (!walkedAtRules.has(rule.parent)) {

}
return;
}
if (isCritical(rule)) {

@@ -104,0 +113,0 @@ critical.append(rule);

@@ -12,6 +12,4 @@ "use strict";

});
var _collect = _interopRequireDefault(require("./collect"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//# sourceMappingURL=index.js.map
{
"name": "@linaria/server",
"version": "4.1.0",
"description": "Blazing fast zero-runtime CSS in JS library",
"version": "4.0.0",
"keywords": [
"css",
"css-in-js",
"linaria",
"react",
"styled-components"
],
"homepage": "https://github.com/callstack/linaria#readme",
"bugs": "https://github.com/callstack/linaria/issues",
"repository": "git@github.com:callstack/linaria.git",
"license": "MIT",
"main": "lib/index.js",
"module": "esm/index.js",
"types": "types",
"files": [
"types/",
"lib/",
"esm/"
],
"dependencies": {

@@ -17,25 +35,7 @@ "postcss": "^8.3.11"

},
"files": [
"types/",
"lib/",
"esm/"
],
"homepage": "https://github.com/callstack/linaria#readme",
"keywords": [
"css",
"css-in-js",
"linaria",
"react",
"styled-components"
],
"license": "MIT",
"main": "lib/index.js",
"module": "esm/index.js",
"publishConfig": {
"access": "public"
},
"repository": "git@github.com:callstack/linaria.git",
"types": "types",
"scripts": {
"build": "npm run build:lib && npm run build:esm && npm run build:declarations",
"build": "pnpm build:lib && pnpm build:esm && pnpm build:declarations",
"build:declarations": "tsc --emitDeclarationOnly --outDir types",

@@ -45,4 +45,4 @@ "build:esm": "babel src --out-dir esm --extensions '.js,.jsx,.ts,.tsx' --source-maps --delete-dir-on-start",

"typecheck": "tsc --noEmit --composite false",
"watch": "npm run build --watch"
"watch": "pnpm build:lib --watch & pnpm build:esm --watch & pnpm build:declarations --watch"
}
}

@@ -1,4 +0,1 @@

/**
* This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments
*/
declare type CollectResult = {

@@ -8,3 +5,15 @@ critical: string;

};
export default function collect(html: string, css: string): CollectResult;
interface ClassnameModifiers {
ignoredClasses?: string[];
blockedClasses?: string[];
}
/**
* This utility extracts critical CSS from given HTML and CSS file to be used in SSR environments
* @param {string} html the HTML from which classes will be parsed
* @param {string} css the CSS file from which selectors will be parsed and determined as critical or other
* @param {string[]} ignoredClasses classes that, when present in the HTML, will not be included in the regular expression used to match selectors
* @param {string[]} blockedClasses classes that, when contained in a selector, will cause the selector to be marked as not critical
* @returns {CollectResult} object containing the critical and other CSS styles
*/
export default function collect(html: string, css: string, classnameModifiers?: ClassnameModifiers): CollectResult;
export {};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc