Comparing version 0.2.6 to 0.3.0
182
index.js
@@ -1,34 +0,32 @@ | ||
var cheerio = require('cheerio'); | ||
var fs = require('fs'); | ||
var sizeOf = require('image-size'); | ||
var request = require('sync-request'); | ||
var cleanCss = require('clean-css'); | ||
const fs = require('fs'); | ||
const url = require('url'); | ||
const cheerio = require('cheerio'); | ||
const request = require('request'); | ||
const sizeOf = require('image-size'); | ||
const CleanCss = require('clean-css'); | ||
module.exports = function(html, options) { | ||
var tags = { | ||
amp: ['img', 'video'] | ||
module.exports = (html, options) => { | ||
const tags = { | ||
amp: ['img', 'video'], | ||
}; | ||
var $, round; | ||
var options = options || {}; | ||
let youtube = false; | ||
options.normalizeWhitespace = options.normalizeWhitespace || false; | ||
options.xmlMode = options.xmlMode || false; | ||
options.decodeEntities = options.decodeEntities || false; | ||
const cheerioOptions = options || { | ||
cwd: options.cwd || '', | ||
round: options.round || true, | ||
normalizeWhitespace: options.normalizeWhitespace || false, | ||
xmlMode: options.xmlMode || false, | ||
decodeEntities: options.decodeEntities || false, | ||
}; | ||
options.cwd = options.cwd || ''; | ||
options.round = options.round || true; | ||
const $ = cheerio.load(html, cheerioOptions); | ||
$ = cheerio.load(html, options); | ||
const round = cheerioOptions.round | ||
? numb => Math.round(numb / 5) * 5 | ||
: numb => numb; | ||
if (options.round) { | ||
round = function(numb) { return Math.round(numb / 5) * 5; } | ||
} | ||
else { | ||
round = function(numb) { return numb; } | ||
} | ||
/* html ⚡ */ | ||
$('html').each(function() { | ||
$(this).attr('amp', ''); | ||
$('html').each((index, element) => { | ||
$(element).attr('amp', ''); | ||
}); | ||
@@ -47,2 +45,33 @@ | ||
/* google analytics */ | ||
$('script').each((index, element) => { | ||
const src = $(element).attr('src'); | ||
if (src) { | ||
const trackingId = src.match(/\bUA-\d{4,10}-\d{1,4}\b/); | ||
if (trackingId) { | ||
$(element).remove(); | ||
$('head').prepend('<script async custom-element="amp-analytics"src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>'); | ||
$('body').append(`<amp-analytics type="googleanalytics"> | ||
<script type="application/json"> | ||
{ "vars": { | ||
"account": "${trackingId}" | ||
}, | ||
"triggers": { | ||
"trackPageview": { | ||
"on": "visible", | ||
"request": "pageview" | ||
} | ||
} | ||
} | ||
</script> | ||
</amp-analytics>`); | ||
} | ||
} | ||
const scriptContent = $(element).html(); | ||
const htmlScriptContent = scriptContent.match(/function gtag\(\){dataLayer\.push\(arguments\);}/); | ||
if (scriptContent && htmlScriptContent) { | ||
$(element).remove(); | ||
} | ||
}); | ||
/* meta viewport */ | ||
@@ -58,64 +87,87 @@ if ($('head meta[content="width=device-width,minimum-scale=1,initial-scale=1"]').length === 0) { | ||
/* body */ | ||
/* img dimensions */ | ||
$('img:not(width):not(height)').each(function() { | ||
var src = $(this).attr('src'); | ||
$('img:not(width):not(height)').each((index, element) => { | ||
const src = $(element).attr('src'); | ||
if (!src) { | ||
return $(this).remove(); | ||
return $(element).remove(); | ||
} | ||
if (src.indexOf('//') === -1) { | ||
var image = options.cwd + '/' + $(this).attr('src'); | ||
const image = `${options.cwd}/${$(element).attr('src')}`; | ||
if (fs.existsSync(image)) { | ||
var size = sizeOf(image); | ||
$(this).attr({ | ||
width: round(size.width), | ||
height: round(size.height) | ||
const size = sizeOf(image); | ||
$(element).attr({ | ||
width: round(size.width), | ||
height: round(size.height), | ||
}); | ||
} | ||
} | ||
else if (src.indexOf('//') != -1) { | ||
var imageUrl = this.attribs.src; | ||
var response = request('GET', imageUrl); | ||
} else if (src.indexOf('//') !== -1) { | ||
const imageUrl = element.attribs.src; | ||
const response = request('GET', imageUrl); | ||
if (response.statusCode === 200) { | ||
var size = sizeOf(response.body); | ||
$(this).attr({ | ||
const size = sizeOf(response.body); | ||
$(element).attr({ | ||
width: round(size.width), | ||
height: round(size.height) | ||
height: round(size.height), | ||
}); | ||
} | ||
}; | ||
} | ||
}); | ||
/* inline styles */ | ||
$('link[rel=stylesheet]').each(function() { | ||
var src = $(this).attr('href'); | ||
var path = src; | ||
var file = ''; | ||
var setFile = function (data) { | ||
var minified = new cleanCss().minify(data).styles; | ||
return '<style amp-custom>' + minified + '</style>'; | ||
$('link[rel=stylesheet]').each((index, element) => { | ||
const src = $(element).attr('href'); | ||
let path = src; | ||
let file = ''; | ||
const setFile = (data) => { | ||
const minified = new CleanCss().minify(data).styles; | ||
return `<style amp-custom>${minified}</style>`; | ||
}; | ||
try { | ||
if (src.indexOf('//') === -1) { | ||
path = options.cwd + '/' + src; | ||
if (fs.existsSync(path)) { | ||
file = setFile(String(fs.readFileSync(path))); | ||
} | ||
} | ||
else if (src.indexOf('//') != -1) { | ||
file = setFile(String(request(path).data)); | ||
}; | ||
} catch (err) { | ||
console.dir(err); | ||
} | ||
try { | ||
if (src.indexOf('//') === -1) { | ||
path = `${options.cwd}/${src}`; | ||
if (fs.existsSync(path)) { | ||
file = setFile(String(fs.readFileSync(path))); | ||
} | ||
} else if (src.indexOf('//') !== -1) { | ||
file = setFile(String(request('GET', path).body)); | ||
} | ||
} catch (err) { | ||
console.dir(err); | ||
} | ||
$(element).replaceWith(file); | ||
}); | ||
$(this).replaceWith(file); | ||
/* youtube */ | ||
$('iframe[src*="http://www.youtube.com"]').each((index, element) => { | ||
youtube = true; | ||
const src = $(element).attr('src'); | ||
const width = $(element).attr('width'); | ||
const height = $(element).attr('height'); | ||
const path = url.parse(src).pathname.split('/'); | ||
const ampYoutube = ` | ||
<amp-youtube | ||
data-videoid="${path[path.length - 1]}" | ||
width="${width}" | ||
height="${height}" | ||
layout="responsive"> | ||
</amp-youtube>`; | ||
$(element).replaceWith(ampYoutube); | ||
}); | ||
if (youtube) { | ||
$('head').prepend('<script async custom-element="amp-youtube" src="https://cdn.ampproject.org/v0/amp-youtube-0.1.js">'); | ||
} | ||
/* amp tags */ | ||
$(tags.amp.join(',')).each(function() { | ||
this.name = 'amp-' + this.name; | ||
$(tags.amp.join(',')).each((index, element) => { | ||
const ampElement = Object.assign(element, { | ||
name: `amp-${element.name}`, | ||
}); | ||
$(element).replaceWith(ampElement); | ||
}); | ||
return $.html(); | ||
} | ||
}; |
{ | ||
"name": "ampify", | ||
"version": "0.2.6", | ||
"version": "0.3.0", | ||
"description": "Convert plain HTML to Google Accelerated Mobile Pages (AMP)", | ||
@@ -15,8 +15,12 @@ "main": "index.js", | ||
"amp-img", | ||
"amp-video" | ||
"amp-video", | ||
"amp-youtube", | ||
"amp-analytics" | ||
], | ||
"license": "MIT", | ||
"scripts": { | ||
"test": "mocha", | ||
"lint": "jshint . && jscs ." | ||
"coverage": "node_modules/.bin/jest --coverage", | ||
"lint": "node_modules/.bin/eslint ./*.js test", | ||
"test": "node_modules/.bin/jest", | ||
"test:watch": "node_modules/.bin/jest --watchAll" | ||
}, | ||
@@ -33,12 +37,12 @@ "repository": { | ||
"cheerio": "^0.22.0", | ||
"clean-css": "^4.0.11", | ||
"image-size": "^0.5.1", | ||
"sync-request": "^4.0.2" | ||
"clean-css": "^4.1.11", | ||
"image-size": "^0.6.2", | ||
"request": "^2.87.0" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"gulp": "^3.9.1", | ||
"gulp-eslint": "^3.0.1", | ||
"gulp-mocha": "^4.3.0" | ||
"eslint": "^4.19.1", | ||
"eslint-config-airbnb-base": "^12.1.0", | ||
"eslint-plugin-import": "^2.12.0", | ||
"jest": "^22.4.4" | ||
} | ||
} |
174
README.md
# ampify | ||
[![NPM Version][npm-image]][npm-url] | ||
[![Downloads Stats][npm-downloads]][npm-url] | ||
[](https://snyk.io/test/github/rkazakov/ampify) | ||
[](https://github.com/facebook/jest) | ||
> Convert plain HTML to Google Accelerated Mobile Pages (AMP). | ||
> Convert plain HTML to Google AMP (Accelerated Mobile Pages) | ||
## Installation | ||
```sh | ||
npm install ampify --save-dev | ||
npm install ampify --save | ||
``` | ||
@@ -16,35 +20,42 @@ | ||
const ampify = require('ampify'); | ||
const html = 'YOUR_HTML_CONTENT'; | ||
const html = '<YOUR_HTML_CONTENT>'; | ||
const amp = ampify(html, {cwd: 'amp'}); | ||
console.log(amp) // Content of AMP HTML | ||
console.log(amp); // Content of AMP HTML | ||
``` | ||
## Options | ||
### cwd | ||
**Assets (images/styles) file path** | ||
Type: `String` | ||
Default: `''` | ||
### Assets (images/styles) file path | ||
- Type: `String` | ||
- Default: `''` | ||
### round | ||
**Enable images dimensions rounding** | ||
Type: `String` | ||
Default: `true` | ||
### Enable images dimensions rounding | ||
- Type: `String` | ||
- Default: `true` | ||
## Example | ||
### Input | ||
```html | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="style.css"> | ||
</head> | ||
<img src="image.png"> | ||
<head> | ||
<link rel="stylesheet" href="styles.css"> | ||
</head> | ||
<img src="image.png"> | ||
</html> | ||
``` | ||
###### image.png | ||
#### image.png | ||
[image.png](/test/image.png) | ||
###### style.css | ||
#### style.css | ||
```css | ||
@@ -57,42 +68,111 @@ body { | ||
### Output | ||
```html | ||
<html amp=""> | ||
<head> | ||
<style amp-custom="">body{background-color:#fff}</style> | ||
</head> | ||
<amp-img src="image.png" width="600" height="400"></amp-img> | ||
<head> | ||
<style amp-custom="">body{background-color:#fff}</style> | ||
</head> | ||
<amp-img src="image.png" width="600" height="400"></amp-img> | ||
</html> | ||
``` | ||
## More examples | ||
See `/examples` folder for full source code. | ||
### Using in Express App | ||
```js | ||
const ampify = require('ampify'); | ||
const express = require('express'); | ||
const app = express(); | ||
app.get('/article', (req, res) => { | ||
const html = ` | ||
<html> | ||
<head> | ||
<title>AMP page</title> | ||
</head> | ||
<body> | ||
<div> | ||
<p>This is an AMP article</p> | ||
</div> | ||
</body> | ||
</html> | ||
`; | ||
const amp = ampify(html, {cwd: 'amp'}); | ||
res.send(amp); // serving AMP content | ||
}); | ||
app.listen(3000, () => { | ||
console.log('Listening on port 3000!'); | ||
}); | ||
``` | ||
### Using as Express middleware | ||
```js | ||
const ampify = require('ampify'); | ||
const express = require('express'); | ||
const app = express(); | ||
app.use((req, res, next) => { | ||
if (req.url.startsWith('/amp')) { | ||
const send = res.send; | ||
res.send = function (html) { | ||
const amp = ampify(html, {cwd: 'amp'}); | ||
send.call(this, amp); | ||
}; | ||
} | ||
next(); | ||
}); | ||
app.get('/amp/article', (req, res) => { | ||
const html = ` | ||
<html> | ||
<head> | ||
<title>AMP page</title> | ||
</head> | ||
<body> | ||
<div> | ||
<p>This is AMP article</p> | ||
</div> | ||
</body> | ||
</html> | ||
`; | ||
res.send(html); | ||
}); | ||
app.get('/article', (req, res) => { | ||
const html = ` | ||
<html> | ||
<head> | ||
<title>HMTL page</title> | ||
</head> | ||
<body> | ||
<div> | ||
<p>This is HTML article</p> | ||
</div> | ||
</body> | ||
</html> | ||
`; | ||
res.send(html); | ||
}); | ||
app.listen(3000, () => { | ||
console.log('Listening on port 3000!'); | ||
}); | ||
``` | ||
## Release History | ||
* 0.2.6 | ||
* UPDATE: unit tests | ||
* 0.2.5 | ||
* UPDATE: head tag charset order | ||
* UPDATE: remove invalid img tag | ||
* UPDATE: unit tests | ||
* UPDATE: readme documentation | ||
* UPDATE: package.json | ||
* 0.2.4 | ||
* UPDATE: package.json | ||
* 0.2.3 | ||
* ADD: meta tag viewport | ||
* ADD: style amp-boilerplate | ||
* 0.2.2 | ||
* ADD: meta tag charset | ||
* ADD: AMP library script tag | ||
* BUG: Options parameter not passing | ||
* 0.2.1 | ||
* ADD: inline styles | ||
* ADD: amp-img tag | ||
* ADD: amp-video tag | ||
* ADD: unit tests | ||
* 0.1.0 | ||
* ADD: AMP HTML tag | ||
* Work in progress | ||
[HISTORY](./HISTORY.md) | ||
## Licence | ||
MIT (c) Ruslan Kazakov | ||
MIT (c) Ruslan Kazakov and [contributors](https://github.com/rkazakov/ampify/graphs/contributors) | ||
[PostXML]: https://github.com/postxml/postxml | ||
@@ -99,0 +179,0 @@ [npm-url]: https://www.npmjs.org/package/ampify |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
12103
153
180
1
+ Addedrequest@^2.87.0
+ Addedajv@6.12.6(transitive)
+ Addedasn1@0.2.6(transitive)
+ Addedassert-plus@1.0.0(transitive)
+ Addedasynckit@0.4.0(transitive)
+ Addedaws-sign2@0.7.0(transitive)
+ Addedaws4@1.13.2(transitive)
+ Addedbcrypt-pbkdf@1.0.2(transitive)
+ Addedcaseless@0.12.0(transitive)
+ Addedcombined-stream@1.0.8(transitive)
+ Addedcore-util-is@1.0.2(transitive)
+ Addeddashdash@1.14.1(transitive)
+ Addeddelayed-stream@1.0.0(transitive)
+ Addedecc-jsbn@0.1.2(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedextsprintf@1.3.0(transitive)
+ Addedfast-deep-equal@3.1.3(transitive)
+ Addedfast-json-stable-stringify@2.1.0(transitive)
+ Addedforever-agent@0.6.1(transitive)
+ Addedform-data@2.3.3(transitive)
+ Addedgetpass@0.1.7(transitive)
+ Addedhar-schema@2.0.0(transitive)
+ Addedhar-validator@5.1.5(transitive)
+ Addedhttp-signature@1.2.0(transitive)
+ Addedimage-size@0.6.3(transitive)
+ Addedis-typedarray@1.0.0(transitive)
+ Addedisstream@0.1.2(transitive)
+ Addedjsbn@0.1.1(transitive)
+ Addedjson-schema@0.4.0(transitive)
+ Addedjson-schema-traverse@0.4.1(transitive)
+ Addedjson-stringify-safe@5.0.1(transitive)
+ Addedjsprim@1.4.2(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addedoauth-sign@0.9.0(transitive)
+ Addedperformance-now@2.1.0(transitive)
+ Addedpsl@1.15.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedqs@6.5.3(transitive)
+ Addedrequest@2.88.2(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsshpk@1.18.0(transitive)
+ Addedtough-cookie@2.5.0(transitive)
+ Addedtunnel-agent@0.6.0(transitive)
+ Addedtweetnacl@0.14.5(transitive)
+ Addeduri-js@4.4.1(transitive)
+ Addeduuid@3.4.0(transitive)
+ Addedverror@1.10.0(transitive)
- Removedsync-request@^4.0.2
- Removedasap@2.0.6(transitive)
- Removedbuffer-from@1.1.2(transitive)
- Removedcall-bind-apply-helpers@1.0.2(transitive)
- Removedcall-bound@1.0.3(transitive)
- Removedcaseless@0.11.0(transitive)
- Removedcommand-exists@1.2.9(transitive)
- Removedconcat-stream@1.6.2(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddunder-proto@1.0.1(transitive)
- Removedes-define-property@1.0.1(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedes-object-atoms@1.1.1(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.3.0(transitive)
- Removedget-port@3.2.0(transitive)
- Removedget-proto@1.0.1(transitive)
- Removedgopd@1.2.0(transitive)
- Removedhas-symbols@1.1.0(transitive)
- Removedhasown@2.0.2(transitive)
- Removedhttp-basic@2.5.1(transitive)
- Removedhttp-response-object@1.1.0(transitive)
- Removedimage-size@0.5.5(transitive)
- Removedisarray@1.0.0(transitive)
- Removedmath-intrinsics@1.1.0(transitive)
- Removedobject-inspect@1.13.4(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedpromise@7.3.1(transitive)
- Removedqs@6.14.0(transitive)
- Removedreadable-stream@2.3.8(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedside-channel@1.1.0(transitive)
- Removedside-channel-list@1.0.0(transitive)
- Removedside-channel-map@1.0.1(transitive)
- Removedside-channel-weakmap@1.0.2(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedsync-request@4.1.0(transitive)
- Removedthen-request@2.2.0(transitive)
- Removedtypedarray@0.0.6(transitive)
Updatedclean-css@^4.1.11
Updatedimage-size@^0.6.2