Skip to content

Commit

Permalink
mv AmpOptimizer to optional-peer-dep; add cleanHtmlCss options overwr…
Browse files Browse the repository at this point in the history
…ites; configurable cssSizeLimit;
  • Loading branch information
elbakerino committed Mar 17, 2022
1 parent 1df1c2a commit 76dff05
Show file tree
Hide file tree
Showing 10 changed files with 1,116 additions and 1,107 deletions.
6 changes: 3 additions & 3 deletions Gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path'
import gulp from 'gulp'
import {ampCreator} from './src/index.js'
import {getPageInfo} from './src/pageTools.js'
import {getPageInfo, ampCreator} from './src/index.js'
import AmpOptimizer from '@ampproject/toolbox-optimizer'

const port = 4488

Expand Down Expand Up @@ -47,7 +47,7 @@ const tasks = ampCreator({
base: 'blog',
pageId: 'example',
}],
ampOptimize: !isDev,
ampOptimizer: !isDev ? AmpOptimizer.create({}) : undefined,
// minifyHtml: false,
cleanInlineCSS: !isDev,
// for css injection of non-AMP pages:
Expand Down
2,009 changes: 997 additions & 1,012 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-amp-page",
"version": "1.0.0-alpha.11",
"version": "1.0.0-beta.0",
"license": "MIT",
"homepage": "https://github.com/bemit/create-amp-page",
"author": "Michael Becker <https://mlbr.xyz>",
Expand Down Expand Up @@ -37,11 +37,20 @@
"clean": "gulp clean"
},
"devDependencies": {
"@formanta/sass": "^0.20.2"
"@formanta/sass": "^0.20.2",
"@ampproject/toolbox-optimizer": "^2.7.4"
},
"peerDependencies": {
"@ampproject/toolbox-optimizer": "^2.7.4"
},
"peerDependenciesMeta": {
"@ampproject/toolbox-optimizer": {
"optional": true
}
},
"dependencies": {
"@ampproject/toolbox-optimizer": "^2.7.4",
"@types/gulp": "^4.0.8",
"@types/html-minifier": "^4.0.2",
"@types/through2": "^2.0.36",
"@types/twig": "^1.12.5",
"autoprefixer": "^10.3.4",
Expand Down
37 changes: 13 additions & 24 deletions src/AmpCreatorOptions.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { extendFilter, extendFunction, extendTest, extendTag } from 'twig'
import { defaults } from 'email-comb'
import { Options as HtmlMinifierOptions } from 'html-minifier'

export type FmMapFiles = {
// the `tpl` file path
Expand Down Expand Up @@ -75,8 +77,6 @@ export interface AmpCreatorOptions {

pages?: {
[page: string]: {
// starts a new proxy on this port
//port?: number
paths: AmpCreatorOptionsPaths
}
}
Expand Down Expand Up @@ -175,39 +175,28 @@ export interface AmpCreatorOptions {
media?: string[]
}

// auto use default configs with `true`;
// or specify custom options, see all:
// https://github.com/ampproject/amp-toolbox/tree/main/packages/optimizer#options
ampOptimize?: boolean | {
autoAddMandatoryTags?: boolean
autoExtensionImport?: boolean
extensionVersions?: Object
format?: string | 'AMP' | 'AMP4EMAIL' | 'AMP4ADS'
imageBasePath?: string | (
/**
* @param imgSrc the path used in `src`
* @param params todo: correctly type this
*/
(imgSrc: string, params: any) => string)
imageOptimizer?: (src: string, width: string | number) => string
lts?: boolean
markdown?: boolean
minify?: boolean
preloadHeroImage?: boolean
verbose?: boolean
}
// enable the ampOptimizer, since 1.0.0-alpha.12 pass down an instance!
ampOptimizer?: any

// custom inject tag, for AMP / default: 'style amp-custom>'
cssInjectTag?: string
// if an `Error` should be thrown when exceeding `cssSizeLimit`
cssFailOnSize?: boolean
// maximum bytes for CSS file, after minimizing, before clean-unused,
// defaults to `75000` bytes (AMP limit)
cssSizeLimit?: number

// remove unused inline CSS
cleanInlineCSS?: boolean
// css selectors which must not be removed, `.classes`, `#ids`, `.simple-whitelist-*`, `h1`, `p`
cleanInlineCSSWhitelist?: string[]
// options for `email-comb` - run when `cleanInlineCSS` is `true`,
// when `cleanInlineCSSOptions` specified the `cleanInlineCSSWhitelist` options does nothing
cleanInlineCSSOptions?: Partial<typeof defaults>

// minify HTML, when not using `ampOptimize`
// minify HTML, when not using `ampOptimizer`
minifyHtml?: boolean
minifyHtmlOptions?: HtmlMinifierOptions

// additional folders to delete
cleanFolders?: string[]
Expand Down
16 changes: 8 additions & 8 deletions src/ampCreator.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ export function ampCreator(options, setup, wrap) {
cleanFolders,
// html / twig
twig,
ampOptimize,
minifyHtml,
cleanInlineCSS,
ampOptimizer,
minifyHtml, minifyHtmlOptions,
cleanInlineCSS, cleanInlineCSSOptions,
cleanInlineCSSWhitelist,
cssInjectTag,
cssFailOnSize,
cssFailOnSize, cssSizeLimit,
pages,
collections,
// media
Expand Down Expand Up @@ -100,13 +100,13 @@ export function ampCreator(options, setup, wrap) {
srcMedia, distMedia,
dist,
twig,
ampOptimize,
minifyHtml,
ampOptimizer,
minifyHtml, minifyHtmlOptions,
imageminPlugins,
cleanInlineCSS,
cleanInlineCSS, cleanInlineCSSOptions,
cleanInlineCSSWhitelist,
cssInjectTag,
cssFailOnSize,
cssFailOnSize, cssSizeLimit,
collections: collections.filter(collection => collection.pageId === pageId || !collection.pageId),
browsersync,
}),
Expand Down
39 changes: 23 additions & 16 deletions src/htmlTask/ampOptimizer.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import through2 from 'through2'
import AmpOptimizer from '@ampproject/toolbox-optimizer'

let ampOptimizerRef = {current: null}
const ampOptimizerLib = AmpOptimizer.create()

export function ampOptimizer(doOptimize) {
if(!ampOptimizerRef.current) {
ampOptimizerRef.current = AmpOptimizer.create(typeof doOptimize === 'object' ? doOptimize : undefined)
}
return through2.obj(async (file, _, cb) => {
/**
* @param {DomTransformer|undefined} ampOptimizerLib
*/
export function ampOptimizer(ampOptimizerLib) {
return through2.obj((file, _, cb) => {
try {
if(doOptimize && file.isBuffer()) {
const optimizedHtml = await ampOptimizerLib.transformHtml(
file.contents.toString(),
{},
)
file.contents = Buffer.from(optimizedHtml)
if(!ampOptimizerLib) {
cb(null, file)
return
}
if(file.isBuffer()) {
ampOptimizerLib.transformHtml(
file.contents.toString(),
{},
)
.then((optimizedHtml) => {
file.contents = Buffer.from(optimizedHtml)
cb(null, file)
})
.catch((e) => {
cb(e)
})
} else {
cb(new Error('ampOptimizer received invalid file'))
}
cb(null, file)
} catch(e) {
cb(e)
}
Expand Down
17 changes: 12 additions & 5 deletions src/htmlTask/cleanHtmlCss.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,28 @@ import through2 from 'through2'
import {minify as htmlmin} from 'html-minifier'
import logger from 'gulplog'

export function cleanHtmlCss({cleanInlineCSS, cleanInlineCSSWhitelist = [], minifyHtml}) {
export function cleanHtmlCss(
{
cleanInlineCSS, cleanInlineCSSOptions, cleanInlineCSSWhitelist = [],
minifyHtml, minifyHtmlOptions,
},
) {
return through2.obj(async (file, _, cb) => {
try {
let startHtmlCSSSize = null
if((cleanInlineCSS || minifyHtml) && file.isBuffer()) {
startHtmlCSSSize = Buffer.byteLength(file.contents.toString(), 'utf8')
logger.info('HTML + CSS Size: ' + startHtmlCSSSize + ' bytes @' + (file.pathData || file.path).substr(file.cwd.length + 1))
logger.info('HTML + CSS Size: ' + startHtmlCSSSize + ' bytes @' + (file.pathData || file.path).slice(file.cwd.length + 1))
}
let cleanedHtmlResult = null
if(cleanInlineCSS && file.isBuffer()) {
cleanedHtmlResult = comb(file.contents.toString(), {whitelist: cleanInlineCSSWhitelist})
cleanedHtmlResult = comb(file.contents.toString(), cleanInlineCSSOptions || {
whitelist: cleanInlineCSSWhitelist,
})
file.contents = Buffer.from(cleanedHtmlResult.result)
}
if(minifyHtml && file.isBuffer()) {
file.contents = Buffer.from(htmlmin(file.contents.toString(), {
file.contents = Buffer.from(htmlmin(file.contents.toString(), minifyHtmlOptions || {
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: false,
collapseWhitespace: true,
Expand All @@ -30,7 +37,7 @@ export function cleanHtmlCss({cleanInlineCSS, cleanInlineCSSWhitelist = [], mini
if(cleanedHtmlResult) {
logger.info('Removed CSS selectors: ' + cleanedHtmlResult.deletedFromBody.length + ' from body and ' + cleanedHtmlResult.deletedFromHead.length + ' from head')
}
logger.info('Cleaned HTML + CSS Size: ' + cleanedHtmlCSSSize + ' bytes, saved ' + (startHtmlCSSSize - cleanedHtmlCSSSize) + ' bytes @' + (file.pathData || file.path).substr(file.cwd.length))
logger.info('Cleaned HTML + CSS Size: ' + cleanedHtmlCSSSize + ' bytes, saved ' + (startHtmlCSSSize - cleanedHtmlCSSSize) + ' bytes @' + (file.pathData || file.path).slice(file.cwd.length))
}
cb(null, file)
} catch(e) {
Expand Down
15 changes: 11 additions & 4 deletions src/htmlTask/htmlTask.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import { AmpCreatorOptions } from '../AmpCreatorOptions'
import { AmpCreatorOptions, AmpCreatorOptionsPaths } from '../AmpCreatorOptions'
import { TaskFunction } from 'undertaker'
import * as stream from 'stream'

export interface MakeTwigHandlerConfig {
twig: AmpCreatorOptions['twig']
paths: AmpCreatorOptions['paths']
ampOptimize: AmpCreatorOptions['ampOptimize']
paths: AmpCreatorOptionsPaths
dist: string
srcMedia: string
distMedia: string
ampOptimizer: AmpCreatorOptions['ampOptimizer']
minifyHtml: AmpCreatorOptions['minifyHtml']
minifyHtmlOptions: AmpCreatorOptions['minifyHtmlOptions']
cleanInlineCSS: AmpCreatorOptions['cleanInlineCSS']
cleanInlineCSSOptions: AmpCreatorOptions['cleanInlineCSSOptions']
cleanInlineCSSWhitelist: AmpCreatorOptions['cleanInlineCSSWhitelist']
cssFailOnSize?: boolean
cssSizeLimit?: number
cssInjectTag: AmpCreatorOptions['cssInjectTag']
cssBuffer?: stream.Transform
}
Expand All @@ -17,7 +24,7 @@ export function makeTwigHandler(config: MakeTwigHandlerConfig): () => Promise<()

export interface MakeHtmlTaskConfig extends MakeTwigHandlerConfig {
twig: AmpCreatorOptions['twig']
paths: AmpCreatorOptions['paths']
paths: AmpCreatorOptionsPaths
collections: AmpCreatorOptions['collections']
browsersync: any | { stream: Function }
additionalHtmlTasks: any[]
Expand Down
48 changes: 26 additions & 22 deletions src/htmlTask/htmlTask.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,20 @@ import {getImage, resizeUsedImages, addImageSuffix} from './twigFnMedia.js'

const {parallel, series, ...gulp} = gulpBase

export const makeTwigHandler = ({
srcMedia, distMedia,
paths, twig,
ampOptimize,
minifyHtml,
cleanInlineCSS,
cleanInlineCSSWhitelist,
cssInjectTag,
cssFailOnSize,
cssBuffer,
}) => {
export const makeTwigHandler = (
{
srcMedia, distMedia,
paths, twig,
ampOptimizer: ampOptimizerLib,
minifyHtml, minifyHtmlOptions,
cleanInlineCSS, cleanInlineCSSOptions,
cleanInlineCSSWhitelist,
cssInjectTag,
cssFailOnSize,
cssSizeLimit,
cssBuffer,
},
) => {
const extendedTwigFunctions = [
getImage(srcMedia, distMedia),
embedScript(paths.dist),
Expand All @@ -37,13 +40,8 @@ export const makeTwigHandler = ({
// share twig logic for `twig-as-entrypoint` and `frontmatter-as-entrypoint` (collections)
if(twig.logicLoader) {
return twig.logicLoader()
.then((logic) => {
// const extraLogic = {
// functions: undefined,
// filters: undefined,
// }
return logic
})
// logic = { functions: undefined, filters: undefined }
.then((logic) => logic)
}
return {}
})
Expand All @@ -70,17 +68,23 @@ export const makeTwigHandler = ({
// middlewares after twig compilation
// middlewares for style injection
.pipe(injectCSS({
paths, injectTag: cssInjectTag,
paths: {
stylesInject: paths.stylesInject,
dist: paths.dist,
distStyles: paths.distStyles,
},
injectTag: cssInjectTag,
failOnSize: cssFailOnSize,
sizeLimit: cssSizeLimit,
cssBuffer: cssBuffer,
}))
// middlewares after CSS injection
.pipe(cleanHtmlCss({
minifyHtml,
cleanInlineCSS,
minifyHtml, minifyHtmlOptions,
cleanInlineCSS, cleanInlineCSSOptions,
cleanInlineCSSWhitelist,
}))
.pipe(ampOptimizer(ampOptimize)),
.pipe(ampOptimizer(ampOptimizerLib)),
)
})
}
Expand Down
21 changes: 11 additions & 10 deletions src/htmlTask/injectCSS.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,35 @@ import replace from 'gulp-replace'
*/
export function injectCSS(
{
paths,
paths: {stylesInject, dist, distStyles} = {},
failOnSize,
sizeLimit = 75000,
injectTag = 'style amp-custom>',
cssBuffer = undefined,
},
) {
return replace(new RegExp(injectTag, 'g'), function() {
if(!paths.stylesInject) return injectTag
if(!stylesInject) return injectTag

let style = ''
try {
if(!cssBuffer) {
style = fs.readFileSync(paths.dist + '/' + paths.distStyles + '/' + paths.stylesInject, 'utf8')
style = fs.readFileSync(dist + '/' + distStyles + '/' + stylesInject, 'utf8')
} else {
style = cssBuffer.contents.toString()
}
if(Buffer.byteLength(style, 'utf8') > 75000) {
logger.error(colors.red('Style Size: ' + (Buffer.byteLength(style, 'utf8')) + ' bytes'))
if(failOnSize) throw new Error('css file exceeds amp limit of 75kb')
} else {
logger.info('Style Size: ' + (Buffer.byteLength(style, 'utf8')) + ' bytes')
}
} catch(err) {
if(failOnSize || err.code !== 'ENOENT') {
if(err.code !== 'ENOENT') {
// only throw if other error then file not-found
throw err
}
}
if(Buffer.byteLength(style, 'utf8') > sizeLimit) {
logger.error(colors.red('Style Size: ' + (Buffer.byteLength(style, 'utf8')) + ' bytes'))
if(failOnSize) throw new Error('css file exceeds amp limit of ' + (sizeLimit / 1000).toFixed(0) + 'kb')
} else {
logger.info('Style Size: ' + (Buffer.byteLength(style, 'utf8')) + ' bytes')
}
return injectTag + '\n' + style + '\n'
})
}

0 comments on commit 76dff05

Please sign in to comment.