GithubHelp home page GithubHelp logo

jhildenbiddle / get-css-data Goto Github PK

View Code? Open in Web Editor NEW
33.0 2.0 8.0 1.33 MB

A micro-library for collecting stylesheet data from link and style nodes

License: MIT License

JavaScript 100.00%
css cssom custom-properties custom-property es6 iframe import javascript legacy link

get-css-data's Introduction

get-css-data

NPM GitHub Workflow Status (master) Codacy code quality Codacy branch coverage License: MIT Sponsor this project

A micro-library for collecting stylesheet data from link and style nodes.

Features

  • Collects CSS data from <link> and <style> nodes
  • Collects static Node.textContent or live CSS Object Model (CSSOM) data
  • Returns CSS data as a concatenated string and a DOM-ordered array of strings
  • Allows document, iframe, and shadow DOM traversal
  • Handles @import rules
  • Handles absolute and relative URLs
  • Inspect, modify and/or filter CSS data from each node
  • Modify XHR object before each request
  • UMD and ES6 modules available
  • Compatible with modern and legacy browsers (IE9+)
  • Lightweight (less than 1.5k min+gzip) and dependency-free

Installation

NPM:

npm install get-css-data --save
// file.js
import getCssData from 'get-css-data';

getCssData({
  onComplete: function(cssText, cssArray, nodeArray) {
    // Do stuff...
  }
});

Git:

git clone https://github.com/jhildenbiddle/get-css-data.git

CDN (jsdelivr.com shown, also on unpkg.com):

<!-- ES5 (latest v2.x.x) -->
<script src="https://cdn.jsdelivr.net/npm/get-css-data@2"></script>
<script>
  getCssData({
    onComplete: function(cssText, cssArray, nodeArray) {
      // Do stuff...
    }
  });
</script>
<!-- ES6 module (latest v2.x.x) -->
<script type="module">
  import getCssData from 'https://cdn.jsdelivr.net/npm/get-css-data@2/dist/get-css-data.esm.min.js';

  getCssData({
    onComplete(cssText, cssArray, nodeArray) {
      // Do stuff...
    }
  });
</script>

Example

HTML:

<!-- file.html -->
<head>
  <link rel="stylesheet" href="style1.css">
  <style>
    @import "style2.css";
    p { color: blue; }
  </style>
</head>

CSS:

/* style1.css */
p { color: red; }
/* style2.css */
p { color: green; }

JavaScript (see Options for details)

getCssData({
  onComplete: function(cssText, cssArray, nodeArray) {
    console.log(cssText); // 1
    console.log(cssArray); // 2
    console.log(nodeArray); // 3
  }
});

// 1 => 'p { color: red; } p { color: green; } p { color: blue; }'
// 2 => ['p { color: red; }', 'p { color: green; } p { color: blue; }']
// 3 => [<linkElement>, <styleElement>]

Options

Example

// Default values shown
getCssData({
  rootElement : document,
  include     : 'link[rel=stylesheet],style',
  exclude     : '',
  filter      : '',
  skipDisabled: true,
  useCSSOM    : false,
  onBeforeSend: function(xhr, node, url) {
    // ...
  },
  onSuccess: function(cssText, node, url) {
    // ...
  },
  onError: function(xhr, node, url) {
    // ...
  },
  onComplete: function(cssText, cssArray, nodeArray) {
    // ...
  }
});

options.rootElement

  • Type: object
  • Default: document

Root element to traverse for <link> and <style> nodes.

Examples

// Document
getCssData({
  rootElement: document // default
});

// Iframe (must be same domain with content loaded)
getCssData({
  rootElement: (myIframe.contentDocument || myIframe.contentWindow.document)
});

// Shadow DOM
getCssData({
  rootElement: myElement.shadowRoot
});

options.include

  • Type: string
  • Default: "link[rel=stylesheet],style"

CSS selector matching <link> and <style> nodes to collect data from. The default value includes all style and link nodes.

Example

getCssData({
  // Include only <link rel="stylesheet"> nodes
  // with an href that does not contains "bootstrap"
  include: 'link[rel=stylesheet]:not([href*=bootstrap])',
});

options.exclude

  • Type: string

CSS selector matching <link> and <style> nodes to exclude from those matched by options.include.

Example

getCssData({
  // Of matched `include` nodes, exclude any node
  // with an href that contains "bootstrap"
  exclude: '[href*=bootstrap]',
});

options.filter

  • Type: object

Regular expression used to filter node CSS data. Each block of CSS data is tested against the filter, and only matching data is processed.

Example

getCssData({
  // Test each block of CSS for the existence
  // of ".myclass". If found, process the CSS.
  // If not, ignore the CSS.
  filter: /\.myclass/,
});

options.skipDisabled

  • Type: boolean
  • Default: true

Determines if disabled stylesheets will be skipped while collecting CSS data.

Example

getCssData({
  skipDisabled: true // default
});

options.useCSSOM

  • Type: boolean
  • Default: false

Determines how CSS data will be collected from <style> nodes.

When false, static CSS data is collected by reading each node's textContent value. This method is fast, but the data collected will not reflect changes made using the deleteRule() or insertRule() methods. When true, live CSS data is collected by iterating over each node's CSSRuleList and concatenating all CSSRule.cssText values into a single string. This method is slower, but the data collected accurately reflects all changes made to the stylesheet.

Keep in mind that browsers often drop unrecognized selectors, properties, and values when parsing static CSS. For example, Chrome/Safari will drop declarations with Mozilla's -moz- prefix, while Firefox will drop declarations with Chrome/Safari's -webkit prefix . This means that data collected when this options is set to true will likely vary between browsers and differ from the static CSS collected when it is set to false.

Example

getCssData({
  useCSSOM: false // default
});

options.onBeforeSend

  • Type: function
  • Arguments:
    1. xhr: The XHR object containing details of the request
    2. node: The source node object reference
    3. url: The source URL string (<link> href or @import url)

Callback before each XMLHttpRequest (XHR) is sent. Allows modifying the XML object by setting properties, calling methods, or adding event handlers.

Example

getCssData({
  onBeforeSend: function(xhr, node, url) {
    // Domain-specific XHR settings
    if (/some-domain.com/.test(url)) {
      xhr.withCredentials = true;
      xhr.setRequestHeader("foo", "1");
      xhr.setRequestHeader("bar", "2");
    }
  }
});

options.onSuccess

  • Type: function
  • Arguments:
    1. cssText: A string of CSS text from node and url
    2. node: The source node object reference
    3. url: The source URL string (<link> href, @import url, or page url for <style> data)

Callback after CSS data has been collected from each node. Allows modifying the CSS data before it is added to the final output by returning any string value or skipping the CSS data by returning false or an empty string ("").

Note that the order in which <link> and @import CSS data is "successfully" collected (thereby triggering this callback) is not guaranteed as these requests are asynchronous. To access CSS data in DOM order, use the cssArray argument passed to the options.oncomplete callback.

Example

getCssData({
  onSuccess: function(cssText, node, url) {
    // Replace all instances of "color: red" with "color: blue"
    const newCssText = cssText.replace(/color:\s*red\s;/g, 'color: blue;');

    return newCssText;
  }
});

options.onError

  • Type: function
  • Arguments:
    1. xhr: The XHR object containing details of the request
    2. node: The source node object reference
    3. url: The source URL string (<link> href or @import url)

Callback after <link> or @import request has failed or when xhr.responseText appears to be HTML instead of CSS.

Example

getCssData({
  onError: function(xhr, node, url) {
    console.log(xhr.status); // 1
    console.log(xhr.statusText); // 2
  }
});

// 1 => '404'
// 2 => 'Not Found'

options.onComplete

  • Type: function
  • Arguments:
    1. cssText: A string of concatenated CSS text from all nodes in DOM order.
    2. cssArray: An array of per-node CSS text in DOM order. The node containing each CSS text block is available at the same nodeArray index.
    3. nodeArray: An array of processed <style> and <link> nodes in DOM order. The CSS text for each node is available at the same cssArray index.

Callback after CSS data has been collected from all nodes.

Example

getCssData({
  onComplete: function(cssText, cssArray, nodeArray) {
    // ...
  }
});

Sponsorship

A sponsorship is more than just a way to show appreciation for the open-source authors and projects we rely on; it can be the spark that ignites the next big idea, the inspiration to create something new, and the motivation to share so that others may benefit.

If you benefit from this project, please consider lending your support and encouraging future efforts by becoming a sponsor.

Thank you! πŸ™πŸ»

Contact & Support

  • Follow πŸ‘¨πŸ»β€πŸ’» @jhildenbiddle on Twitter and GitHub for announcements
  • Create a πŸ’¬ GitHub issue for bug reports, feature requests, or questions
  • Add a ⭐️ star on GitHub and 🐦 tweet to promote the project
  • Become a πŸ’– sponsor to support the project and future efforts

License

This project is licensed under the MIT License. See the LICENSE for details.

Copyright (c) John Hildenbiddle (@jhildenbiddle)

get-css-data's People

Contributors

jhildenbiddle avatar markbarbieri avatar wggit2020 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

get-css-data's Issues

xmlhttprequest not support file protocol

if the link protocol is file,such as β€œfile:///E:/a.css”
will be blocked,
error meesage is " origin 'null' has been blocked by cors policy: cross origin requests are only support protocol schemes: http ,data,chrome,chrome-extension,chrome-untrustef,https"

html link is

Thanks.

Honor CSS in HTML imports

It would be convenient for this library to support link[rel=import] as a possible include setting. For example polyfilling (or ponyfilling) CSS custom properties would become significantly easier for utilities that depend on this one. That would allow broader support of web components that expect to use CSS variables, as the common method for using web components is via HTML imports.

That means this library would look at HTML imports, and apply the other rules present in the include setting to get their css data.

For instance, if we have an HTML file that is imported, "import1.html" and that HTML file has a style tag in its content, then get-css-data would return the CSS styles found in that style tag, assuming that the include setting has the selector style in it. There would be a similar outcome with another imported HTML file, "import2.html" that has a link to a stylesheet in it, should the include setting have the selector link[rel="stylesheet"].

I've already started looking into the code to see how this could be supported.

One concern is recursive crawling of HTML imports. I haven't gotten that far yet!

getCssData doesn't respect page's <base> href when building URLs for CSS download

Hi, I'm using css-vars-ponyfill which using get-css-data and I found that page's <base> tag's href not taken into account when it downloads CSS sources by JS. Fortunately css-vars-ponyfill provides onBeforeSend hook and I was able to solve that issue in the next way:

cssVars({
  updateURLs: false,
  onBeforeSend: function(xhr, elm, url) {
    var baseUrl = document.querySelector('base').getAttribute('href');
    xhr.open('GET', url.replace(location.origin + '/', baseUrl)); // fix to respect base URL
  }
});

Wrong URL requested was: https://mydomain/1.css
Correct URL should be: https://cdn.something.com/mydomain/1.css (because of <base href="https://cdn.something.com/mydomain/">)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.