From 9faeb4eb1e22ed06d9e90931abc0453d8f8d87ca Mon Sep 17 00:00:00 2001 From: Jere Menichelli Date: Thu, 8 Aug 2019 11:20:26 +0200 Subject: [PATCH] fix: correct named export --- src/css.js | 104 +++++++++++++++++++++++++++++++++++++++++++++ src/index.js | 105 +--------------------------------------------- src/index.test.js | 22 +++++----- 3 files changed, 116 insertions(+), 115 deletions(-) create mode 100644 src/css.js diff --git a/src/css.js b/src/css.js new file mode 100644 index 0000000..3b376da --- /dev/null +++ b/src/css.js @@ -0,0 +1,104 @@ +/** + * Fallback function + * @method noop + * @returns {undefined} + */ +const noop = () => {} + +/** + * Method called when a stylesheet is loaded + * @method __onload__ + * @param {Object} config + */ +function __onload__(media, storage, logger) { + this.onload = null + this.media = media || 'all' + + logger(null, `${this.href} loaded asynchronously`) + + if (storage) { + try { + const rules = this.sheet ? this.sheet.cssRules : this.styleSheet.rules + let styles = rules.reduce((acc, rule) => { + return (acc += rule.cssText) + }, '') + + // wrap rules with @media statement if necessary + if (media) styles = `@media ${media} {${styles}}` + + // save on web storage + window[`${storage}Storage`].setItem(this.href, styles) + } catch (e) { + logger(e, 'Stylesheet could not be saved for future visits') + } + } +} + +/** + * Loads stylesheet asynchronously or retrieves it from web storage + * @method css + * @param {Object} config + */ +function css(config = {}) { + const script = document.getElementsByTagName('script')[0] + const ref = config.ref || script + const logger = config.logger || noop + const link = document.createElement('link') + let storedStyles + let el + + // create link element to extract correct href path + link.rel = 'stylesheet' + link.href = config.url + + /* + * Detect stored stylesheet content only when storage option is present + * and expose an error in console in case web storage is not supported + */ + if (config.storage) { + try { + storedStyles = window[`${config.storage}Storage`].getItem(link.href) + } catch (error) { + logger( + error, + `${link.href} could not be retrieved from ${config.storage}Storage` + ) + } + } + + /* + * if stylesheet is in web storage inject a style tag with its + * content, else load it using the link tag + */ + if (storedStyles) { + el = document.createElement('style') + + el.textContent = storedStyles + + logger(null, `${link.href} retrieved from ${config.storage}Storage`) + } else { + /* + * Filament Group approach to prevent stylesheet to block rendering + * https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js#L26 + */ + link.media = 'only x' + + /* + * Add crossOrigin attribute for external stylesheets, take in count this + * attribute is not widely supported. In those cases CSS rules will not be + * saved in web storage but stylesheet will be loaded + */ + if (config.crossOrigin) link.crossOrigin = config.crossOrigin + + link.onload = __onload__.bind(link, config.media, config.storage, logger) + el = link + } + + /* + * Node insert approach taken from Paul Irish's 'Surefire DOM Element Insertion' + * http://www.paulirish.com/2011/surefire-dom-element-insertion/ + */ + ref.parentNode.insertBefore(el, ref) +} + +export default css diff --git a/src/index.js b/src/index.js index 22d7c45..09b40df 100644 --- a/src/index.js +++ b/src/index.js @@ -1,104 +1 @@ -/** - * Fallback function - * @method noop - * @returns {undefined} - */ -const noop = () => {} - -/** - * Method called when a stylesheet is loaded - * @method __onload__ - * @param {Object} config - */ -function __onload__(media, storage, logger) { - this.onload = null - this.media = media || 'all' - - logger(null, `${this.href} loaded asynchronously`) - - if (storage) { - try { - const rules = this.sheet ? this.sheet.cssRules : this.styleSheet.rules - let styles = rules.reduce((acc, rule) => { - return (acc += rule.cssText) - }, '') - - // wrap rules with @media statement if necessary - if (media) styles = `@media ${media} {${styles}}` - - // save on web storage - window[`${storage}Storage`].setItem(this.href, styles) - } catch (e) { - logger(e, 'Stylesheet could not be saved for future visits') - } - } -} - -/** - * Loads stylesheet asynchronously or retrieves it from web storage - * @method css - * @param {Object} config - */ -function css(config = {}) { - const script = document.getElementsByTagName('script')[0] - const ref = config.ref || script - const logger = config.logger || noop - const link = document.createElement('link') - let storedStyles - let el - - // create link element to extract correct href path - link.rel = 'stylesheet' - link.href = config.url - - /* - * Detect stored stylesheet content only when storage option is present - * and expose an error in console in case web storage is not supported - */ - if (config.storage) { - try { - storedStyles = window[`${config.storage}Storage`].getItem(link.href) - } catch (error) { - logger( - error, - `${link.href} could not be retrieved from ${config.storage}Storage` - ) - } - } - - /* - * if stylesheet is in web storage inject a style tag with its - * content, else load it using the link tag - */ - if (storedStyles) { - el = document.createElement('style') - - el.textContent = storedStyles - - logger(null, `${link.href} retrieved from ${config.storage}Storage`) - } else { - /* - * Filament Group approach to prevent stylesheet to block rendering - * https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js#L26 - */ - link.media = 'only x' - - /* - * Add crossOrigin attribute for external stylesheets, take in count this - * attribute is not widely supported. In those cases CSS rules will not be - * saved in web storage but stylesheet will be loaded - */ - if (config.crossOrigin) link.crossOrigin = config.crossOrigin - - link.onload = __onload__.bind(link, config.media, config.storage, logger) - el = link - } - - /* - * Node insert approach taken from Paul Irish's 'Surefire DOM Element Insertion' - * http://www.paulirish.com/2011/surefire-dom-element-insertion/ - */ - ref.parentNode.insertBefore(el, ref) -} - -export default { css } +export { default as css } from './css' diff --git a/src/index.test.js b/src/index.test.js index 1b296eb..82a051b 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -1,4 +1,4 @@ -import store from '.' +import { css } from '.' import test from 'ava' import sinon from 'sinon' import clone from 'lodash.clonedeep' @@ -69,7 +69,7 @@ test.afterEach(() => { test('loads stylesheet', (t) => { const url = 'https://path.to/stylesheet.css' - store.css({ url }) + css({ url }) // assigned link properties correctly t.is(ELEMENTS.link.href, url) @@ -94,7 +94,7 @@ test('loads stylesheet', (t) => { test('accepts media in config object', (t) => { const url = 'https://path.to/stylesheet.css' const media = '(max-width: 739px' - store.css({ url, media }) + css({ url, media }) ELEMENTS.link.onload() t.is(ELEMENTS.link.media, media) @@ -103,7 +103,7 @@ test('accepts media in config object', (t) => { test('accepts cross origin attribute', (t) => { const url = 'https://path.to/stylesheet.css' const crossOrigin = 'anonymous' - store.css({ url, crossOrigin }) + css({ url, crossOrigin }) t.is(ELEMENTS.link.crossOrigin, crossOrigin) }) @@ -111,7 +111,7 @@ test('accepts cross origin attribute', (t) => { test('accepts a reference element for link injection', (t) => { const url = 'https://path.to/stylesheet.css' const ref = { parentNode: { insertBefore: sinon.spy() } } - store.css({ url, ref }) + css({ url, ref }) t.is(ref.parentNode.insertBefore.getCall(0).args[0], ELEMENTS.link) t.is(ref.parentNode.insertBefore.getCall(0).args[1], ref) @@ -120,7 +120,7 @@ test('accepts a reference element for link injection', (t) => { test('stores result in localStorage', (t) => { const url = 'https://path.to/stylesheet.css' const storage = 'local' - store.css({ url, storage }) + css({ url, storage }) // styles gets to local storage ELEMENTS.link.onload() @@ -132,7 +132,7 @@ test('stores result in localStorage', (t) => { test('stores result in sessionStorage', (t) => { const url = 'https://path.to/stylesheet.css' const storage = 'session' - store.css({ url, storage }) + css({ url, storage }) // styles gets to session storage ELEMENTS.link.onload() @@ -146,7 +146,7 @@ test('retrieves already saved styles from localStorage', (t) => { const storage = 'local' const styles = `${firstRule}${secondRule}` window.localStorage[url] = styles - store.css({ url, storage }) + css({ url, storage }) t.is(window.localStorage.getItem.getCall(0).args[0], url) t.is(ELEMENTS.style.textContent, styles) @@ -157,7 +157,7 @@ test('retrieves already saved styles from sessionStorage', (t) => { const storage = 'session' const styles = `${firstRule}${secondRule}` window.sessionStorage[url] = styles - store.css({ url, storage }) + css({ url, storage }) t.is(window.sessionStorage.getItem.getCall(0).args[0], url) t.is(ELEMENTS.style.textContent, styles) @@ -168,7 +168,7 @@ test('wraps styles in media when storing', (t) => { const media = '(max-width: 739px)' const storage = 'session' const styles = `${firstRule}${secondRule}` - store.css({ url, media, storage }) + css({ url, media, storage }) ELEMENTS.link.onload() t.is( @@ -181,7 +181,7 @@ test('accepts logger method', (t) => { const url = 'https://path.to/stylesheet.css' const storage = 'session' const logger = sinon.spy() - store.css({ url, storage, logger }) + css({ url, storage, logger }) ELEMENTS.link.onload() t.is(logger.getCall(0).args[0], null)