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

gulp-resource-hints

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

gulp-resource-hints - npm Package Compare versions

Comparing version 0.1.2 to 0.2.0

1

lib/defaults.js

@@ -6,2 +6,3 @@ 'use strict'

getCSSAssets: true,
silent: false,
paths: {

@@ -8,0 +9,0 @@ 'dns-prefetch': '//*',

222

lib/helpers.js

@@ -6,10 +6,13 @@ 'use strict'

const Soup = require('soup')
const gutil = require('gulp-util')
const parse = require('url').parse
const defaults = require('./defaults')
var appOptions = {}
var appLoaded = false
const PLUGIN_NAME = 'gulp-resource-hints'
var parsedAssets = []
var parsedAssets = [] // helps check for duplicates
var insertionPoint = '' // dictates where to insert resource hints
// const PLUGIN_NAME = 'gulp-resource-hints'
var fonts = [

@@ -59,7 +62,2 @@ '**/*.woff',

function clearParsedAssets () {
parsedAssets = []
}
module.exports.clearParsedAssets = clearParsedAssets
/**

@@ -71,2 +69,8 @@ * Checking duplicates is necessary for dns-prefetch and prefetch

*/
/**
* Check for duplicates in parsedAssets helper array
* @param {string} assetToCheck
* @param {boolean} isHost
*/
function isDuplicate (assetToCheck, isHost) {

@@ -85,4 +89,88 @@ if (parsedAssets.length <= 0) {

// Checks if asset matches user glob pattern
// Writes resource hint if it does
/**
* Unset helper variables
*/
function reset () {
parsedAssets = []
insertionPoint = ''
}
module.exports.reset = reset
/**
* Log to the console unless user opts out
* @param {string} message
* @param {boolean} warn
*/
function logger (message, warn) {
if (appOptions.silent) {
return
}
if (warn) {
console.warn(message)
return
}
console.log(message)
}
module.exports.logger = logger
/**
* Determine if file has a valid area to inject resource hints
* @param {stream} file
*/
function hasInsertionPoint (file) {
var token = appOptions.pageToken
if (token !== '' && String(file.contents).indexOf(token) > -1) {
insertionPoint = 'token'
} else if (token !== '' && token !== defaults.pageToken) {
logger('Token not found in ' + file.relative)
}
var soup = new Soup(String(file.contents))
// Append after metas
soup.setInnerHTML('head > meta:last-of-type', function (oldHTML) {
if (oldHTML !== null) {
insertionPoint = 'meta'
return oldHTML
}
})
if (insertionPoint) {
return true
}
// Else, prepend before links
soup.setInnerHTML('head > link:first-of-type', function (oldHTML) {
if (oldHTML !== null) {
insertionPoint = 'link'
return oldHTML
}
})
if (insertionPoint) {
return true
}
// Else, append to head
soup.setInnerHTML('head', function (oldHTML) {
if (oldHTML !== null) {
insertionPoint = 'head'
return oldHTML
}
})
return insertionPoint
}
module.exports.hasInsertionPoint = hasInsertionPoint
/**
* Validate asset is desireable by user
* Build resource hint if so
* @param {string} hint
* @param {string} asset
* @param {string} glob
* @return {string}
*/
function buildResourceHint (hint, asset, glob) {

@@ -116,75 +204,65 @@ var as = ''

function mergeOptions (userOpts) {
// iterate over existing keys
/**
* Merge user options with defaults
* @param {object} userOpts
* @return {object}
*/
function options (userOpts) {
if (appLoaded && typeof userOpts === 'undefined') {
return appOptions
}
userOpts = typeof userOpts === 'object' ? userOpts : {}
appOptions = Object.assign({}, defaults, userOpts)
appOptions.paths = Object.assign({}, defaults.paths, userOpts.paths)
appLoaded = true
var options = {}
return appOptions
}
module.exports.options = options
if (!userOpts) {
return defaults
} else {
var iterate = function (obj) {
for (var key in defaults) {
if (typeof obj[key] === 'object' && typeof defaults[key] !== 'object') {
// Deep compare if object found
iterate(obj[key])
} else if (!obj[key] && defaults[key] !== '') {
// Use non-blank default since there is no user option
options[key] = defaults[key]
} else if (typeof defaults[key] === typeof obj[key]) {
// Use user-defined value only if the type matches
options[key] = obj[key]
}
}
}
/**
* Write resource hints to file
* @param {stream} file
* @param {string} data
* @param {string} token
* @return {string}
*/
function writeDataToFile (file, data, token) {
// insertionPoint was set in hasInsertionPoint(), so we can assume it is safe to write to file
var selectors = [
'head > meta:last-of-type',
'head > link:first-of-type',
'head'
]
var selectorIndex = 0
iterate(userOpts)
return options
switch (insertionPoint) {
case 'meta':
selectorIndex = 0
break
case 'link':
selectorIndex = 1
break
case 'head':
selectorIndex = 2
break
case 'token':
let html = String(file.contents).replace(token, data)
return new Buffer(html)
default:
return ''
}
}
module.exports.mergeOptions = mergeOptions
function writeData (file, data, token) {
if (token !== '' && String(file.contents).indexOf(token) > -1) {
let html = String(file.contents).replace(token, data)
return new Buffer(html)
}
if (token !== '' && token !== defaults.pageToken) {
gutil.log(PLUGIN_NAME, 'Provided token was not found in: ' + file.relative + '\nWill attempt to append to <head>')
}
var soup = new Soup(String(file.contents))
var hasMeta = false
var hasLink = false
var hasHead = false
// Append after metas
soup.setInnerHTML('head > meta:last-of-type', function (oldHTML) {
hasMeta = true
// Inject Resource Hints
soup.setInnerHTML(selectors[selectorIndex], function (oldHTML) {
if (insertionPoint === 'link') {
return data + oldHTML
}
return oldHTML + data
})
// Else, prepend before links
if (!hasMeta) {
soup.setInnerHTML('head > link:first-of-type', function (oldHTML) {
hasLink = true
return data + oldHTML
})
}
// Else, append to head
if (!hasMeta && !hasLink) {
soup.setInnerHTML('head', function (oldHTML) {
hasHead = true
return oldHTML + data
})
}
// No head? Oh noes!
if (!hasHead) {
gutil.log(PLUGIN_NAME, 'No document <head> found, cannot write resource hints. Skipping file:', file.relative)
return false
}
return soup.toString()
}
module.exports.writeData = writeData
module.exports.writeDataToFile = writeDataToFile
'use strict'
const listAssets = require('list-assets')
const gutil = require('gulp-util')
const Transform = require('stream').Transform

@@ -10,10 +9,16 @@

/**
* Main Function
* Read file streams, parse assets, build resource hints
* @param {object} opt
*/
function gulpResourceHints (opt) {
var options = helpers.mergeOptions(opt)
var options = helpers.options(opt)
helpers.reset()
var stream = new Transform({
return new Transform({
objectMode: true,
transform: function (file, enc, cb) {
if (file.isNull()) {
gutil.log(PLUGIN_NAME, 'no file')
helpers.logger(PLUGIN_NAME, 'no file', true)

@@ -26,4 +31,5 @@ cb(null, file)

// Gather assets
var assets = listAssets.html(
// Gather assets, keep unique values
// Using https://www.npmjs.com/package/list-assets
var assets = new Set(listAssets.html(
fileContents,

@@ -34,7 +40,6 @@ {

}
).map((ob) => {
return ob.url
})
).map(ob => ob.url))
if (assets.length < 0) {
if (assets.size < 0) {
// Skip file: no static assets
cb(null, file)

@@ -44,3 +49,7 @@ return

helpers.clearParsedAssets()
if (!helpers.hasInsertionPoint(file)) {
helpers.logger(PLUGIN_NAME, 'Skipping file: no <head> or token found', true)
cb(null, file)
return
}

@@ -59,5 +68,5 @@ // Future feature! Gotta do more stream madness

// Build resource hints based on user-selected assets
var data = ''
var data = ['']
for (var i = 0, len = assets.length; i < len; i++) {
assets.forEach((aVal, aKey, set) => {
Object.keys(options.paths).forEach((key) => {

@@ -67,9 +76,11 @@ if (options.paths[key] === '') {

}
data += helpers.buildResourceHint(key, assets[i], options.paths[key])
data.push(helpers.buildResourceHint(key, aVal, options.paths[key]))
})
}
})
var newFile = helpers.writeData(file, data, options.pageToken)
data = data.reduce((a, b) => a + b)
var newFile = helpers.writeDataToFile(file, data, options.pageToken)
if (!newFile) {
helpers.logger(PLUGIN_NAME + ': Could not write data to file. ' + file.relative)
cb(null, file)

@@ -84,6 +95,4 @@ return

})
return stream
}
module.exports = gulpResourceHints
{
"name": "gulp-resource-hints",
"version": "0.1.2",
"version": "0.2.0",
"description": "Add resource hints to your html files",

@@ -43,3 +43,2 @@ "main": "lib/index.js",

"dependencies": {
"gulp-util": "^3.0.8",
"is-css": "^2.0.0",

@@ -49,3 +48,8 @@ "list-assets": "0.0.2",

"soup": "^0.1.5"
},
"standard": {
"ignore": [
"**/node_modules/**"
]
}
}

@@ -75,2 +75,3 @@ # gulp-resource-hints

- `pageToken <String>` : add your own custom string replace token (default is **##gulp-resource-hints##**)
- `silent <Boolean>` : disable logs and warnings (default is `false`)
- `paths <Object>` : custom string patterns for their respective resource hint.

@@ -113,2 +114,6 @@ - `dns-prefetch <String>` : custom [URL pattern](#url-patterns). Default is `//*` (all non-relative URLs)

## Changelog
See [latest release](https://github.com/theetrain/gulp-resource-hints/releases/latest).
---

@@ -115,0 +120,0 @@

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