postcss-font-grabber
Advanced tools
Comparing version 2.2.1 to 3.0.0-alpha.1
/// <reference types="node" /> | ||
import postcss from 'postcss'; | ||
import { Declaration } from 'postcss'; | ||
import url from 'url'; | ||
import { PluginOptions, PluginSettings, RemoteFont, Job, JobResult } from '../contracts'; | ||
import { Downloader as DownloaderContract } from './downloader/contract'; | ||
export declare function parseOptions(options: PluginOptions): PluginSettings; | ||
export declare function isRemoteFontFaceDeclaration(node: postcss.ChildNode): boolean; | ||
import { ParsedSrc, FontSpec, DownloadResult } from '../types'; | ||
export declare function isRemoteFontFaceDeclaration(node: Declaration): boolean; | ||
export declare function isFontFaceSrcContainsRemoteFontUri(cssValue: string): boolean; | ||
export declare function getFontFilename(fontUriObject: url.UrlWithStringQuery): string; | ||
export declare function getFontFormatFromUrlObject(urlObject: url.UrlWithStringQuery): undefined | string; | ||
export declare function getFontInfoFromSrc(src: string): undefined | RemoteFont; | ||
export declare function reduceSrcsToFontInfos(fontInfos: RemoteFont[], src: string): RemoteFont[]; | ||
export declare function processDeclaration(declaration: postcss.Declaration, cssSourceFilePath: string, cssDestinationDirectoryPath: string, downloadDirectoryPath: string): Job[]; | ||
export declare function downloadFont(job: Job, downloader?: DownloaderContract): Promise<JobResult>; | ||
export declare function calculateCssOutputDirectoryPath(cssSourceFilePath: string, cssSourceDirectoryPathFromSetting: string | undefined, cssDestinationDirectoryPathFromSetting: string | undefined, postcssOptionsTo: string | undefined): string | undefined; | ||
export declare function guessFormatFromUrl(urlObject: url.UrlWithStringQuery): string | undefined; | ||
export declare function parseSrcString(src: string): undefined | ParsedSrc; | ||
export declare function calculateFontId(fontUrl: url.UrlWithStringQuery): string; | ||
export declare function getSourceCssFilePath(node: Declaration): string; | ||
export declare function calculateFontSpecs(fontFaceNode: Declaration): FontSpec[]; | ||
export declare function getFormatForFontExtension(extension: string): string | null; | ||
export declare function getFontExtensionForFormat(format: string): string; | ||
export declare function getFontFileExtentionForMimeType(mimeType: string): string | null; | ||
export declare function getExtensionForBasename(basename: string): string; | ||
export declare function getFontFileExtention({ format, mimeType, basename, }: { | ||
format?: string; | ||
mimeType?: string; | ||
basename: string; | ||
}): string; | ||
export declare function saveFile({ downloadResult, fontSpec, fontDirectoryPath, }: { | ||
downloadResult: DownloadResult; | ||
fontSpec: FontSpec; | ||
fontDirectoryPath: string; | ||
}): Promise<{ | ||
filename: string; | ||
filePath: string; | ||
format: string | null; | ||
}>; | ||
export declare function calculateRelativePath({ cssDirectoryPath, cssFileDirectoryRelativePath, fontFilePath, }: { | ||
cssDirectoryPath: string; | ||
cssFileDirectoryRelativePath: string; | ||
fontFilePath: string; | ||
}): string; | ||
export declare function getNewDeclarationValue({ value, oldUrl, newUrl, }: { | ||
value: string; | ||
oldUrl: string; | ||
newUrl: string; | ||
}): string; | ||
export declare function getSubDirectoryPath(directoryPath: string, subFilePath: string): string; |
@@ -6,23 +6,24 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.calculateCssOutputDirectoryPath = exports.downloadFont = exports.processDeclaration = exports.reduceSrcsToFontInfos = exports.getFontInfoFromSrc = exports.getFontFormatFromUrlObject = exports.getFontFilename = exports.isFontFaceSrcContainsRemoteFontUri = exports.isRemoteFontFaceDeclaration = exports.parseOptions = void 0; | ||
exports.getSubDirectoryPath = exports.getNewDeclarationValue = exports.calculateRelativePath = exports.saveFile = exports.getFontFileExtention = exports.getExtensionForBasename = exports.getFontFileExtentionForMimeType = exports.getFontExtensionForFormat = exports.getFormatForFontExtension = exports.calculateFontSpecs = exports.getSourceCssFilePath = exports.calculateFontId = exports.parseSrcString = exports.guessFormatFromUrl = exports.getFontFilename = exports.isFontFaceSrcContainsRemoteFontUri = exports.isRemoteFontFaceDeclaration = void 0; | ||
const path_1 = __importDefault(require("path")); | ||
const url_1 = __importDefault(require("url")); | ||
const fs_1 = require("fs"); | ||
const helpers_1 = require("../helpers"); | ||
const downloader_1 = require("./downloader"); | ||
const fontExtensionToFormatMap = { | ||
'.eot': 'embedded-opentype', | ||
'.woff': 'woff', | ||
'.woff2': 'woff2', | ||
'.ttf': 'truetype', | ||
'.svg': 'svg', | ||
const console_1 = require("console"); | ||
const errors_1 = require("./errors"); | ||
const FontExtensionsToMimeTypes = { | ||
woff: ['application/font-woff', 'font/woff'], | ||
woff2: ['application/font-woff2', 'font/woff2'], | ||
eot: ['application/vnd.ms-fontobject'], | ||
ttf: ['application/x-font-ttf', 'application/x-font-truetype'], | ||
otf: ['application/x-font-opentype', 'font/otf'], | ||
svg: ['image/svg+xml'], | ||
}; | ||
function parseOptions(options) { | ||
return { | ||
cssSourceDirectoryPath: options.cssSrc !== undefined ? path_1.default.resolve(options.cssSrc) : undefined, | ||
cssDestinationDirectoryPath: options.cssDest !== undefined ? path_1.default.resolve(options.cssDest) : undefined, | ||
fontDirectoryPath: options.fontDir !== undefined ? path_1.default.resolve(options.fontDir) : undefined, | ||
autoCreateDirectory: helpers_1.defaultValue(options.mkdir, true), | ||
}; | ||
} | ||
exports.parseOptions = parseOptions; | ||
const FontExtensionsToFormats = { | ||
eot: 'embedded-opentype', | ||
woff: 'woff', | ||
woff2: 'woff2', | ||
ttf: 'truetype', | ||
svg: 'svg', | ||
}; | ||
function isRemoteFontFaceDeclaration(node) { | ||
@@ -55,3 +56,3 @@ if (node.type !== 'decl') { | ||
exports.getFontFilename = getFontFilename; | ||
function getFontFormatFromUrlObject(urlObject) { | ||
function guessFormatFromUrl(urlObject) { | ||
if (!urlObject.pathname) { | ||
@@ -61,8 +62,6 @@ return; | ||
const extension = path_1.default.extname(urlObject.pathname); | ||
return fontExtensionToFormatMap[extension] !== undefined ? | ||
fontExtensionToFormatMap[extension] : | ||
undefined; | ||
return FontExtensionsToFormats[extension.substring(1)]; | ||
} | ||
exports.getFontFormatFromUrlObject = getFontFormatFromUrlObject; | ||
function getFontInfoFromSrc(src) { | ||
exports.guessFormatFromUrl = guessFormatFromUrl; | ||
function parseSrcString(src) { | ||
const result = /^url\s*\(\s*[\'\"]?(https?:[^\)]*?)[\'\"]?\s*\)(\s+format\([\'\"]?([a-zA-Z0-9]+)[\'\"]?\))?/.exec(src); | ||
@@ -73,5 +72,5 @@ if (result === null) { | ||
const urlObject = url_1.default.parse(result[1]); | ||
const format = result[3] !== undefined ? result[3] : getFontFormatFromUrlObject(urlObject); | ||
const format = result[3] !== undefined ? result[3] : guessFormatFromUrl(urlObject); | ||
if (format === undefined) { | ||
throw new Error(`can't get the font format from @font-face src: [${src}]`); | ||
console_1.debug(`can't get the font format from @font-face src: [${src}]`); | ||
} | ||
@@ -83,43 +82,30 @@ return { | ||
} | ||
exports.getFontInfoFromSrc = getFontInfoFromSrc; | ||
function reduceSrcsToFontInfos(fontInfos, src) { | ||
const fontInfo = getFontInfoFromSrc(src); | ||
return fontInfo === undefined ? | ||
fontInfos : | ||
[...fontInfos, fontInfo]; | ||
exports.parseSrcString = parseSrcString; | ||
function calculateFontId(fontUrl) { | ||
return helpers_1.md5(url_1.default.format(fontUrl)); | ||
} | ||
exports.reduceSrcsToFontInfos = reduceSrcsToFontInfos; | ||
function processDeclaration(declaration, cssSourceFilePath, cssDestinationDirectoryPath, downloadDirectoryPath) { | ||
const relativePath = path_1.default.relative(cssDestinationDirectoryPath, downloadDirectoryPath); | ||
const fontFaceSrcs = declaration.value.split(',').map(helpers_1.trim); | ||
const fontInfos = fontFaceSrcs.reduce(reduceSrcsToFontInfos, []); | ||
return fontInfos.map(fontInfo => { | ||
const filename = getFontFilename(fontInfo.urlObject); | ||
const filePath = path_1.default.resolve(path_1.default.join(downloadDirectoryPath, filename)); | ||
const job = { | ||
remoteFont: fontInfo, | ||
css: { | ||
sourcePath: cssSourceFilePath, | ||
destinationDirectoryPath: cssDestinationDirectoryPath, | ||
}, | ||
font: { | ||
path: filePath, | ||
filename: filename, | ||
}, | ||
}; | ||
const originalUri = url_1.default.format(fontInfo.urlObject); | ||
const replaceTo = path_1.default.join(relativePath, job.font.filename) | ||
.replace(/\\/g, '/'); | ||
declaration.value = declaration.value.replace(originalUri, replaceTo); | ||
return job; | ||
}); | ||
exports.calculateFontId = calculateFontId; | ||
function getSourceCssFilePath(node) { | ||
var _a, _b; | ||
const sourceFile = (_b = (_a = node.source) === null || _a === void 0 ? void 0 : _a.input) === null || _b === void 0 ? void 0 : _b.file; | ||
if (sourceFile === undefined) { | ||
throw new errors_1.PostcssFontGrabberError(`Can not get CSS file path of the node: "${node.toString()}"`); | ||
} | ||
return sourceFile; | ||
} | ||
exports.processDeclaration = processDeclaration; | ||
function downloadFont(job, downloader = new downloader_1.Downloader()) { | ||
return downloader.download(job.remoteFont.urlObject, job.font.path) | ||
.then(fileInfo => { | ||
exports.getSourceCssFilePath = getSourceCssFilePath; | ||
function calculateFontSpecs(fontFaceNode) { | ||
const srcs = fontFaceNode.value.split(',').map(helpers_1.trim); | ||
const filteredAndParsedSrcs = srcs.reduce((parsedSrcs, src) => { | ||
const parsed = parseSrcString(src); | ||
return parsed ? [...parsedSrcs, parsed] : parsedSrcs; | ||
}, []); | ||
return filteredAndParsedSrcs.map(parsedSrc => { | ||
var _a; | ||
return { | ||
job, | ||
download: { | ||
size: fileInfo.size, | ||
id: calculateFontId(parsedSrc.urlObject), | ||
parsedSrc, | ||
basename: path_1.default.basename((_a = parsedSrc.urlObject.pathname) !== null && _a !== void 0 ? _a : ''), | ||
css: { | ||
sourceFile: getSourceCssFilePath(fontFaceNode), | ||
}, | ||
@@ -129,15 +115,83 @@ }; | ||
} | ||
exports.downloadFont = downloadFont; | ||
function calculateCssOutputDirectoryPath(cssSourceFilePath, cssSourceDirectoryPathFromSetting, cssDestinationDirectoryPathFromSetting, postcssOptionsTo) { | ||
const cssDirectoryPath = path_1.default.dirname(cssSourceFilePath); | ||
const finalPostcssOptionsTo = helpers_1.defaultValue(postcssOptionsTo, undefined); | ||
const cssSourceDirectoryPath = helpers_1.defaultValue(cssSourceDirectoryPathFromSetting, cssDirectoryPath); | ||
const cssDestinationDirectoryPath = helpers_1.defaultValue(cssDestinationDirectoryPathFromSetting, (finalPostcssOptionsTo !== undefined ? path_1.default.dirname(finalPostcssOptionsTo) : undefined)); | ||
if (cssDestinationDirectoryPath === undefined) { | ||
return undefined; | ||
exports.calculateFontSpecs = calculateFontSpecs; | ||
function getFormatForFontExtension(extension) { | ||
const format = FontExtensionsToFormats[extension]; | ||
return format === undefined ? null : format; | ||
} | ||
exports.getFormatForFontExtension = getFormatForFontExtension; | ||
function getFontExtensionForFormat(format) { | ||
const lowerCased = format.toLowerCase(); | ||
for (const [extension, format] of Object.entries(FontExtensionsToFormats)) { | ||
if (format === lowerCased) { | ||
return extension; | ||
} | ||
} | ||
const cssToSourceDirectoryRelation = path_1.default.relative(cssSourceDirectoryPath, cssDirectoryPath); | ||
return path_1.default.join(cssDestinationDirectoryPath, cssToSourceDirectoryRelation); | ||
throw new errors_1.PostcssFontGrabberError(`Invalid format: "${format}", please check your CSS rule.`); | ||
} | ||
exports.calculateCssOutputDirectoryPath = calculateCssOutputDirectoryPath; | ||
exports.getFontExtensionForFormat = getFontExtensionForFormat; | ||
function getFontFileExtentionForMimeType(mimeType) { | ||
const lowerCased = mimeType.toLowerCase(); | ||
for (const [extension, mimeTypes] of Object.entries(FontExtensionsToMimeTypes)) { | ||
if (mimeTypes.includes(lowerCased)) { | ||
return extension; | ||
} | ||
} | ||
return null; | ||
} | ||
exports.getFontFileExtentionForMimeType = getFontFileExtentionForMimeType; | ||
function getExtensionForBasename(basename) { | ||
return path_1.default.extname(basename).replace(/^\./, ''); | ||
} | ||
exports.getExtensionForBasename = getExtensionForBasename; | ||
function getFontFileExtention({ format, mimeType, basename, }) { | ||
if (format) { | ||
return getFontExtensionForFormat(format); | ||
} | ||
if (mimeType) { | ||
const mimeTypeExtension = getFontFileExtentionForMimeType(mimeType); | ||
if (mimeTypeExtension !== null) { | ||
return mimeTypeExtension; | ||
} | ||
} | ||
return getExtensionForBasename(basename); | ||
} | ||
exports.getFontFileExtention = getFontFileExtention; | ||
function saveFile({ downloadResult, fontSpec, fontDirectoryPath, }) { | ||
var _a; | ||
const extension = getFontFileExtention({ | ||
format: fontSpec.parsedSrc.format, | ||
mimeType: downloadResult.mimeType, | ||
basename: fontSpec.basename, | ||
}); | ||
const finalFormat = (_a = fontSpec.parsedSrc.format) !== null && _a !== void 0 ? _a : getFormatForFontExtension(extension); | ||
const filename = `${fontSpec.id}${extension === '' ? '' : `.${extension}`}`; | ||
const filePath = path_1.default.join(fontDirectoryPath, filename); | ||
return new Promise((resolve, reject) => { | ||
const file = fs_1.createWriteStream(filePath); | ||
file.on('error', error => reject(error)); | ||
file.on('finish', () => resolve({ | ||
filename, | ||
filePath, | ||
format: finalFormat, | ||
})); | ||
downloadResult.data.pipe(file); | ||
}); | ||
} | ||
exports.saveFile = saveFile; | ||
function calculateRelativePath({ cssDirectoryPath, cssFileDirectoryRelativePath, fontFilePath, }) { | ||
const filename = path_1.default.basename(fontFilePath); | ||
const fontDirectoryPath = path_1.default.dirname(fontFilePath); | ||
const cssFilePath = path_1.default.join(cssDirectoryPath, cssFileDirectoryRelativePath); | ||
return path_1.default.join(path_1.default.relative(cssFilePath, fontDirectoryPath), filename); | ||
} | ||
exports.calculateRelativePath = calculateRelativePath; | ||
function getNewDeclarationValue({ value, oldUrl, newUrl, }) { | ||
return value.replace(oldUrl, newUrl); | ||
} | ||
exports.getNewDeclarationValue = getNewDeclarationValue; | ||
function getSubDirectoryPath(directoryPath, subFilePath) { | ||
const relativeFilePath = path_1.default.relative(directoryPath, subFilePath); | ||
return path_1.default.dirname(relativeFilePath); | ||
} | ||
exports.getSubDirectoryPath = getSubDirectoryPath; | ||
//# sourceMappingURL=functions.js.map |
/// <reference types="node" /> | ||
import EventEmitter from 'events'; | ||
import { Transformer as PostcssTransformer } from 'postcss'; | ||
import postcss from 'postcss'; | ||
import { PluginSettings, JobResult, DoneCallback } from '../contracts'; | ||
import { Result as PostcssResult, Plugin as PostcssPlugin } from 'postcss'; | ||
import { PluginOptions, Downloader } from '../types'; | ||
export declare function resolvePathIfNotUndefined(pathOrUndefined?: string): string | undefined; | ||
export declare class FontGrabber { | ||
protected downloader: Downloader; | ||
protected doneEmitter: EventEmitter; | ||
protected downloadJobs: void[]; | ||
protected settings: PluginSettings; | ||
constructor(settings: PluginSettings); | ||
protected done(jobResults: JobResult[]): void; | ||
protected getOptionFromPostcssResult(result: postcss.Result | undefined, key: string): string | undefined; | ||
makeTransformer(): PostcssTransformer; | ||
onDone(callback: DoneCallback): void; | ||
protected createDirectoryIfWantTo(directoryPath: string): Promise<void>; | ||
protected cssSourceDirectoryPath?: string; | ||
protected cssDestinationDirectoryPath?: string; | ||
protected fontDirectoryPath?: string; | ||
constructor({ cssSrc, cssDest, fontDest, downloader, }: PluginOptions); | ||
protected getOptionFromPostcssResult(result: PostcssResult | undefined, key: string): string | undefined; | ||
createPlugin(): PostcssPlugin; | ||
} |
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -6,21 +15,24 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.FontGrabber = void 0; | ||
exports.FontGrabber = exports.resolvePathIfNotUndefined = void 0; | ||
const events_1 = __importDefault(require("events")); | ||
const util_1 = require("util"); | ||
const url_1 = __importDefault(require("url")); | ||
const path_1 = __importDefault(require("path")); | ||
const functions_1 = require("./functions"); | ||
const helpers_1 = require("../helpers"); | ||
const constants_1 = require("../constants"); | ||
const download_1 = require("./download"); | ||
const errors_1 = require("./errors"); | ||
const debug = util_1.debuglog('PostcssFontGrabber - FontGrabber'); | ||
function resolvePathIfNotUndefined(pathOrUndefined) { | ||
return pathOrUndefined ? path_1.default.resolve(pathOrUndefined) : undefined; | ||
} | ||
exports.resolvePathIfNotUndefined = resolvePathIfNotUndefined; | ||
class FontGrabber { | ||
constructor(settings) { | ||
constructor({ cssSrc, cssDest, fontDest, downloader = download_1.downloadFontFile, }) { | ||
this.doneEmitter = new events_1.default(); | ||
this.settings = settings; | ||
this.downloadJobs = []; | ||
this.downloader = downloader; | ||
this.cssSourceDirectoryPath = resolvePathIfNotUndefined(cssSrc); | ||
this.cssDestinationDirectoryPath = resolvePathIfNotUndefined(cssDest); | ||
this.fontDirectoryPath = resolvePathIfNotUndefined(fontDest); | ||
} | ||
done(jobResults) { | ||
const meta = { | ||
jobResults: jobResults, | ||
}; | ||
this.doneEmitter.emit('done', meta); | ||
} | ||
getOptionFromPostcssResult(result, key) { | ||
@@ -35,36 +47,72 @@ if (result === undefined) { | ||
} | ||
makeTransformer() { | ||
return (root, result) => { | ||
debug(`CSS file: [${root.source.input.file}]`); | ||
const postcssOptionsTo = this.getOptionFromPostcssResult(result, 'to'); | ||
const cssOutputToDirectory = functions_1.calculateCssOutputDirectoryPath(root.source.input.file, this.settings.cssSourceDirectoryPath, this.settings.cssDestinationDirectoryPath, postcssOptionsTo); | ||
const fontOutputToDirectory = helpers_1.defaultValue(this.settings.fontDirectoryPath, cssOutputToDirectory); | ||
if (cssOutputToDirectory === undefined || fontOutputToDirectory === undefined) { | ||
throw new Error(`Can not determine output file path`); | ||
} | ||
debug(`css output to: [${cssOutputToDirectory}]`); | ||
debug(`font output to: [${fontOutputToDirectory}]`); | ||
const jobs = []; | ||
const declarationProcessor = node => { | ||
if (functions_1.isRemoteFontFaceDeclaration(node)) { | ||
jobs.push(...functions_1.processDeclaration(node, root.source.input.file, cssOutputToDirectory, fontOutputToDirectory)); | ||
createPlugin() { | ||
return { | ||
postcssPlugin: 'postcss-font-grabber', | ||
prepare: result => { | ||
var _a, _b, _c; | ||
const postcssResultOptions = result.opts; | ||
const cssSourceDirectoryPath = (_a = this.cssSourceDirectoryPath) !== null && _a !== void 0 ? _a : postcssResultOptions.from; | ||
const cssDestinationDirectoryPath = (_b = this.cssDestinationDirectoryPath) !== null && _b !== void 0 ? _b : postcssResultOptions.to; | ||
if (cssSourceDirectoryPath === undefined) { | ||
throw new errors_1.PostcssFontGrabberError(`Must know where the source CSS files are stored to calculate relative URLs.`); | ||
} | ||
}; | ||
root.walkAtRules(/font-face/, rule => rule.each(declarationProcessor)); | ||
const uniqueJobs = helpers_1.unique(jobs, job => helpers_1.md5(url_1.default.format(job.remoteFont.urlObject) + job.css.sourcePath)); | ||
return this.createDirectoryIfWantTo(fontOutputToDirectory) | ||
.then(() => Promise.all(uniqueJobs.map(job => functions_1.downloadFont(job)))) | ||
.then(jobResults => this.done(jobResults)); | ||
if (cssDestinationDirectoryPath === undefined) { | ||
throw new errors_1.PostcssFontGrabberError(`Could not determine where the processed CSS files are stored, so postcss-font-grabber does not know how to update your CSS rules.`); | ||
} | ||
const fontDirectoryPath = (_c = this.fontDirectoryPath) !== null && _c !== void 0 ? _c : cssDestinationDirectoryPath; | ||
const downloaded = {}; | ||
return { | ||
Once: () => __awaiter(this, void 0, void 0, function* () { | ||
yield helpers_1.makeDirectoryRecursively(fontDirectoryPath); | ||
}), | ||
OnceExit: () => { | ||
}, | ||
AtRule: (rule) => __awaiter(this, void 0, void 0, function* () { | ||
if (rule[constants_1.RuleProcessed]) { | ||
return; | ||
} | ||
if (rule.name !== 'font-face') { | ||
return; | ||
} | ||
rule[constants_1.RuleProcessed] = true; | ||
for (const node of rule.nodes) { | ||
if (node.type !== 'decl') { | ||
continue; | ||
} | ||
if (!functions_1.isRemoteFontFaceDeclaration(node)) { | ||
continue; | ||
} | ||
const fontSpecs = functions_1.calculateFontSpecs(node); | ||
for (const fontSpec of fontSpecs) { | ||
const fontUrlString = fontSpec.parsedSrc.urlObject.href; | ||
if (!downloaded[fontUrlString]) { | ||
const downloadResult = yield this.downloader(fontSpec); | ||
const details = yield functions_1.saveFile({ | ||
downloadResult, | ||
fontSpec, | ||
fontDirectoryPath, | ||
}); | ||
downloaded[fontUrlString] = Object.assign(Object.assign({}, details), { fontSpec }); | ||
} | ||
const downloadDetails = downloaded[fontUrlString]; | ||
const cssFileDirectoryRelativePath = functions_1.getSubDirectoryPath(cssSourceDirectoryPath, downloadDetails.fontSpec.css.sourceFile); | ||
const relativePath = functions_1.calculateRelativePath({ | ||
cssDirectoryPath: cssDestinationDirectoryPath, | ||
cssFileDirectoryRelativePath, | ||
fontFilePath: downloadDetails.filePath, | ||
}); | ||
node.value = functions_1.getNewDeclarationValue({ | ||
value: node.value, | ||
oldUrl: fontUrlString, | ||
newUrl: relativePath, | ||
}); | ||
} | ||
} | ||
}), | ||
}; | ||
}, | ||
}; | ||
} | ||
onDone(callback) { | ||
this.doneEmitter.on('done', callback); | ||
} | ||
createDirectoryIfWantTo(directoryPath) { | ||
return this.settings.autoCreateDirectory === true ? | ||
helpers_1.makeDirectoryRecursively(directoryPath) : | ||
Promise.resolve(); | ||
} | ||
} | ||
exports.FontGrabber = FontGrabber; | ||
//# sourceMappingURL=index.js.map |
@@ -1,7 +0,5 @@ | ||
import postcss from 'postcss'; | ||
import { PluginOptions } from './contracts'; | ||
import { FontGrabber } from './font-grabber'; | ||
declare function makeInstance(options: PluginOptions | undefined): FontGrabber; | ||
declare const plugin: postcss.Plugin<PluginOptions>; | ||
export { makeInstance, plugin as postcssFontGrabber, }; | ||
export default plugin; | ||
import { PluginCreator } from 'postcss'; | ||
import { PluginOptions } from './types'; | ||
declare const postcssFontGrabber: PluginCreator<PluginOptions>; | ||
export { postcssFontGrabber }; | ||
export default postcssFontGrabber; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.postcssFontGrabber = exports.makeInstance = void 0; | ||
const postcss_1 = __importDefault(require("postcss")); | ||
exports.postcssFontGrabber = void 0; | ||
const font_grabber_1 = require("./font-grabber"); | ||
const functions_1 = require("./font-grabber/functions"); | ||
function makeInstance(options) { | ||
if (options === undefined) { | ||
throw new Error(`You must specify plugin options.`); | ||
} | ||
return new font_grabber_1.FontGrabber(functions_1.parseOptions(options)); | ||
} | ||
exports.makeInstance = makeInstance; | ||
const plugin = postcss_1.default.plugin('postcss-font-grabber', options => { | ||
return makeInstance(options).makeTransformer(); | ||
}); | ||
exports.postcssFontGrabber = plugin; | ||
exports.default = plugin; | ||
const postcssFontGrabber = (options = {}) => { | ||
const fontGrabber = new font_grabber_1.FontGrabber(options); | ||
return fontGrabber.createPlugin(); | ||
}; | ||
exports.postcssFontGrabber = postcssFontGrabber; | ||
postcssFontGrabber.postcss = true; | ||
exports.default = postcssFontGrabber; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "postcss-font-grabber", | ||
"version": "2.2.1", | ||
"version": "3.0.0-alpha.1", | ||
"description": "Grab remote font files in @font-face, download them and update your CSS, just like that.", | ||
@@ -13,3 +13,8 @@ "author": "AaronJan <aaronjan@qq.com>", | ||
"main": "dist/index.js", | ||
"types": "./index.d.ts", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist", | ||
"LICENSE", | ||
"README.md" | ||
], | ||
"engines": { | ||
@@ -22,3 +27,4 @@ "node": ">=10.0.0" | ||
"test:cov": "jest --coverage", | ||
"build": "tsc", | ||
"pretty": "npx prettier --write {src,tests}/**/*.ts", | ||
"build": "rimraf -rf dist && tsc", | ||
"prepare": "npm run build" | ||
@@ -35,16 +41,20 @@ }, | ||
"devDependencies": { | ||
"@types/gulp": "^4.0.6", | ||
"@types/gulp": "^4.0.8", | ||
"@types/jest": "^23.3.14", | ||
"@types/node": "^12.12.62", | ||
"@types/sinon": "^9.0.5", | ||
"@types/node": "^12.19.15", | ||
"@types/sinon": "^9.0.10", | ||
"coveralls": "^3.1.0", | ||
"gulp": "^4.0.2", | ||
"jest": "^26.4.2", | ||
"sinon": "^9.0.3", | ||
"ts-jest": "^26.4.0", | ||
"typescript": "^4.0.3" | ||
"gulp-postcss": "^9.0.0", | ||
"jest": "^26.6.3", | ||
"postcss": "^8.0.0", | ||
"prettier": "^2.2.1", | ||
"rimraf": "^3.0.2", | ||
"sinon": "^9.2.4", | ||
"ts-jest": "^26.5.0", | ||
"typescript": "^4.1.3" | ||
}, | ||
"dependencies": { | ||
"postcss": ">=6 <=8" | ||
"peerDependencies": { | ||
"postcss": "^8.0.0" | ||
} | ||
} |
215
README.md
@@ -8,3 +8,3 @@ <h1 align=center> | ||
<a href="https://www.npmjs.com/package/postcss-font-grabber"><img src="https://img.shields.io/npm/dt/postcss-font-grabber.svg?style=flat-square" alt="Downloads"></a> | ||
<a href="https://travis-ci.org/AaronJan/postcss-font-grabber"><img src="https://img.shields.io/travis/AaronJan/postcss-font-grabber.svg?style=flat-square" alt="Build Status"></a> | ||
<a href="https://github.com/aaronjan/postcss-font-grabber"><img src="https://github.com/aaronjan/postcss-font-grabber/workflows/Node.js%20CI/badge.svg?branch=master" alt="Build status" /></a> | ||
<a href="https://coveralls.io/github/AaronJan/postcss-font-grabber?branch=master"><img src="https://img.shields.io/coveralls/AaronJan/postcss-font-grabber.svg?style=flat-square" alt="Coverage Status"></a> | ||
@@ -14,6 +14,7 @@ <a href="https://www.npmjs.com/package/postcss-font-grabber"><img src="https://img.shields.io/npm/l/postcss-font-grabber.svg?style=flat-square" alt="License"></a> | ||
> 🎉 Here is the brand new `2.0` version that is completely rewritten in TypeScript (with typing), for `1.0` please see [HERE](https://github.com/AaronJan/postcss-font-grabber/tree/v1.x) | ||
> `3.x` is under active development. | ||
A [`PostCSS`](https://github.com/postcss/postcss) plugin, it only does one thing and good at it: **download remote fonts that's in your CSS file (`@font-face`)**. | ||
A [`PostCSS`](https://github.com/postcss/postcss) plugin, it only does one thing and good at it: **download remote fonts, and update the corresponding `@font-face` rules**. | ||
> `postcss-font-grabber` `v3.x` only works with `postcss` `v8`,for `postcss` `v7`, please take a look at the [`v2.x`](https://github.com/AaronJan/postcss-font-grabber/tree/v1.x). | ||
@@ -24,25 +25,21 @@ ## Motivation | ||
* it may expose your internal project | ||
* font service may be slow for your users | ||
* you can do more things with local font files | ||
- it may expose your internal project | ||
- font service may be slow for your users | ||
- you can do more things with local font files | ||
- GDPR compliance | ||
## Features | ||
* Written in TypeScript | ||
* Standalone without any dependency | ||
* Concurrent download | ||
* Automatically create directories | ||
* Support HTTP & HTTPS | ||
- Written in TypeScript | ||
- Standalone without any dependency | ||
- Download font files concurrently | ||
## Installation | ||
> Requires: `Node >= 8.0` | ||
> Requires: `Node >= 8.0`, `postcss 8.*` | ||
``` | ||
npm install postcss-font-grabber --save-dev | ||
npm install postcss postcss-font-grabber --save-dev | ||
``` | ||
## Usages | ||
@@ -54,21 +51,23 @@ | ||
gulp.task('css', () => { | ||
const postcss = require('gulp-postcss'); | ||
const { postcssFontGrabber } = require('postcss-font-grabber'); | ||
const postcss = require('gulp-postcss'); | ||
const { postcssFontGrabber } = require('postcss-font-grabber'); | ||
return gulp.src('src/css/**/*.css') | ||
.pipe(postcss([ | ||
postcssFontGrabber({ | ||
// Because PostCSS-Font-Grabber can't get the paths outside itself, you | ||
// have to set them manually. | ||
cssSrc: 'src/css/', | ||
cssDest: 'dist/', | ||
fontDir: 'dist/fonts/', | ||
mkdir: true, | ||
}), | ||
])) | ||
.pipe(gulp.dest('dist/')); | ||
return gulp | ||
.src('src/css/**/*.css') | ||
.pipe( | ||
postcss([ | ||
postcssFontGrabber({ | ||
// Because PostCSS-Font-Grabber can't get the paths outside itself, you | ||
// have to set them manually. | ||
cssSrc: 'src/css/', | ||
cssDest: 'dist/', | ||
fontDest: 'dist/fonts/', | ||
mkdir: true, | ||
}), | ||
]), | ||
) | ||
.pipe(gulp.dest('dist/')); | ||
}); | ||
``` | ||
### With Webpack | ||
@@ -78,5 +77,5 @@ | ||
> | ||
> * [postcss-loader](https://github.com/postcss/postcss-loader) | ||
> * [css-loader](https://github.com/webpack-contrib/css-loader) | ||
> * [file-loader](https://github.com/webpack-contrib/file-loader) | ||
> - [postcss-loader](https://github.com/postcss/postcss-loader) | ||
> - [css-loader](https://github.com/webpack-contrib/css-loader) | ||
> - [file-loader](https://github.com/webpack-contrib/file-loader) | ||
@@ -89,36 +88,34 @@ `webpack.config.js`: | ||
module.exports = { | ||
entry: './src/index.js', | ||
output: { | ||
filename: 'bundle.js', | ||
path: path.resolve(__dirname, 'dist'), | ||
}, | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.css$/, | ||
exclude: /node_modules/, | ||
use: [ | ||
{ | ||
loader: 'style-loader', | ||
}, | ||
{ | ||
loader: 'css-loader', | ||
options: { | ||
importLoaders: 1, | ||
} | ||
}, | ||
{ | ||
loader: 'postcss-loader' | ||
}, | ||
], | ||
entry: './src/index.js', | ||
output: { | ||
filename: 'bundle.js', | ||
path: path.resolve(__dirname, 'dist'), | ||
}, | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.css$/, | ||
exclude: /node_modules/, | ||
use: [ | ||
{ | ||
loader: 'style-loader', | ||
}, | ||
{ | ||
loader: 'css-loader', | ||
options: { | ||
importLoaders: 1, | ||
}, | ||
{ | ||
test: /\.(woff|woff2|eot|ttf|otf)$/, | ||
use: [ | ||
'file-loader' | ||
] | ||
}, | ||
] | ||
} | ||
} | ||
}, | ||
{ | ||
loader: 'postcss-loader', | ||
}, | ||
], | ||
}, | ||
{ | ||
test: /\.(woff|woff2|eot|ttf|otf)$/, | ||
use: ['file-loader'], | ||
}, | ||
], | ||
}, | ||
}; | ||
``` | ||
@@ -132,22 +129,20 @@ | ||
module.exports = { | ||
plugins: [ | ||
postcssFontGrabber({ | ||
cssSrc: 'src/css/', | ||
// When using with `Webpack` you must set `cssDest` as the same as `cssSrc` | ||
// since `Webpack` doesn't output CSS files directly, when done with | ||
// `PostCSS`, `Webpack` use `file-loader` to transpile local file | ||
// references in the CSS. | ||
cssDest: 'src/css/', | ||
fontDir: 'tmp/css/fonts/', | ||
}), | ||
] | ||
} | ||
plugins: [ | ||
postcssFontGrabber({ | ||
cssSrc: 'src/css/', | ||
// When using with `Webpack` you must set `cssDest` as the same as `cssSrc` | ||
// since `Webpack` doesn't output CSS files directly, when done with | ||
// `PostCSS`, `Webpack` use `file-loader` to transpile local file | ||
// references in the CSS. | ||
cssDest: 'src/css/', | ||
fontDest: 'tmp/css/fonts/', | ||
}), | ||
], | ||
}; | ||
``` | ||
### With Only PostCSS | ||
`PostCSS-Font-Grabber` will use `from` and `to` options of `PostCSS` setting as the default options of `cssSrc` (`from`), `cssDest` and `fontDir` (`to`). | ||
`PostCSS-Font-Grabber` will use `from` and `to` options of `PostCSS` setting as the default options of `cssSrc` (`from`), `cssDest` and `fontDest` (`to`). | ||
## Options | ||
@@ -159,17 +154,16 @@ | ||
postcssFontGrabber({ | ||
cssSrc: 'src/css/', | ||
cssDest: 'dist/', | ||
fontDir: 'dist/fonts/', | ||
mkdir: true, | ||
}) | ||
cssSrc: 'src/css/', | ||
cssDest: 'dist/', | ||
fontDest: 'dist/fonts/', | ||
mkdir: true, | ||
}); | ||
``` | ||
|Name|Type|Default|Description| | ||
|:--:|:--:|:------|:----------| | ||
|cssSrc|{string}|`opts.from` from `PostCSS`'s setting|The root directory path of all CSS files| | ||
|cssDest|{string}|`opts.to` from `PostCSS`'s setting|The directory where the transpiled CSS files are in| | ||
|fontDir|{string}|the same as `cssDest`|The directory where the downloaded fonts stored| | ||
|mkdir|{boolean}|`true`|whether to create non-existing directories automatically or not| | ||
| Name | Type | Default | Description | | ||
| :------: | :-------: | :----------------------------------- | :-------------------------------------------------------------- | | ||
| cssSrc | {string} | `opts.from` from `PostCSS`'s setting | The root directory path of all CSS files | | ||
| cssDest | {string} | `opts.to` from `PostCSS`'s setting | The directory where the transpiled CSS files are in | | ||
| fontDest | {string} | the same as `cssDest` | The directory where the downloaded fonts stored | | ||
| mkdir | {boolean} | `true` | whether to create non-existing directories automatically or not | | ||
## Dig Deeper | ||
@@ -184,20 +178,19 @@ | ||
gulp.task('default', () => { | ||
// Create instance manually: | ||
const fontGrabber = makeInstance({ | ||
cssSrc: 'src/css/', | ||
cssDest: 'dist/', | ||
fontDir: 'dist/fonts/', | ||
mkdir: true, | ||
}); | ||
// Create instance manually: | ||
const fontGrabber = makeInstance({ | ||
cssSrc: 'src/css/', | ||
cssDest: 'dist/', | ||
fontDest: 'dist/fonts/', | ||
mkdir: true, | ||
}); | ||
// Register a callback: | ||
fontGrabber.onDone(meta => { | ||
console.log('meta', JSON.stringify(meta, null, ' ')); | ||
}); | ||
// Register a callback: | ||
fontGrabber.onDone(meta => { | ||
console.log('meta', JSON.stringify(meta, null, ' ')); | ||
}); | ||
return gulp.src('src/css/**/*.css') | ||
.pipe(postcss([ | ||
fontGrabber.makeTransformer(), | ||
])) | ||
.pipe(gulp.dest('dist/')); | ||
return gulp | ||
.src('src/css/**/*.css') | ||
.pipe(postcss([fontGrabber.makeTransformer()])) | ||
.pipe(gulp.dest('dist/')); | ||
}); | ||
@@ -240,3 +233,2 @@ ``` | ||
## License | ||
@@ -246,3 +238,2 @@ | ||
## Credits | ||
@@ -249,0 +240,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58960
27
579
14
1
235
3
- Removedpostcss@>=6 <=8