@nuxtjs/icon
Version:
👉 Please refer to [nuxt-community/pwa-module](https://github.com/nuxt-community/pwa-module) for documentation.
179 lines (150 loc) • 4.41 kB
JavaScript
const fs = require('fs-extra')
const path = require('path')
const hasha = require('hasha')
const { fork } = require('child_process')
const { joinUrl, getRouteParams } = require('@nuxtjs/pwa-utils')
module.exports = function (options) {
this.nuxt.hook('build:before', () => run.call(this, options, true))
if (this.options.mode === 'spa' && !this.options.dev) {
return run.call(this, options, false) // Fill meta
}
}
async function run (moduleOptions, _emitAssets) {
const { publicPath } = getRouteParams(this.options)
// Defaults
const defaults = {
iconFileName: 'icon.png',
sizes: [64, 120, 144, 152, 192, 384, 512],
targetDir: 'icons',
accessibleIcons: true,
iconProperty: '$icon',
publicPath,
iconSrc: null,
_iconHash: null,
_cacheDir: null,
_icons: null,
_assetIcons: null
}
// Merge options
const options = {
...defaults,
...this.options.icon,
...moduleOptions
}
// Find iconSrc
options.iconSrc = await findIcon.call(this, options)
// Disable module if no icon specified
if (!options.iconSrc) {
return
}
// Generate icons
await generateIcons.call(this, options)
// Add manifest
addManifest.call(this, options)
// Add plugin
if (options.accessibleIcons) {
addPlugin.call(this, options)
}
// Emit assets in background
if (_emitAssets) {
emitAssets.call(this, options)
}
}
async function findIcon (options) {
const iconSearchPath = [
options.iconSrc,
path.resolve(this.options.srcDir, this.options.dir.static, options.iconFileName),
path.resolve(this.options.srcDir, this.options.dir.assets, options.iconFileName)
].filter(p => p)
for (const iconSrc of iconSearchPath) {
if (await fs.exists(iconSrc)) {
return iconSrc
}
}
}
async function addPlugin (options) {
const icons = {}
for (const icon of options._assetIcons) {
icons[icon.sizes] = icon.src
}
if (options.accessibleIcons) {
this.addPlugin({
src: path.resolve(__dirname, './plugin.js'),
fileName: 'nuxt-icons.js',
options: {
iconProperty: options.iconProperty,
icons
}
})
}
}
async function generateIcons (options) {
// Get hash of source image
if (!options.iconHash) {
options.iconHash = await hasha.fromFile(options.iconSrc).then(h => h.substring(0, 6))
}
if (!options._cacheDir) {
options._cacheDir = path.join(__dirname, '.cache', options.iconHash)
}
// Generate _icons
options._icons = {}
for (const size of options.sizes) {
options._icons[size] = `${options.targetDir}/icon_${size}.${options.iconHash}.png`
}
// Generate _assetIcons
options._assetIcons = options.sizes.map(size => ({
src: joinUrl(options.publicPath, options._icons[size]),
sizes: `${size}x${size}`,
type: `image/png`
}))
}
function addManifest (options) {
if (!this.options.manifest) {
this.options.manifest = {}
}
if (!this.options.manifest.icons) {
this.options.manifest.icons = []
}
this.options.manifest.icons.push(...options._assetIcons)
}
function emitAssets (options) {
// Start resize task in background
const resizePromise = resizeIcons.call(this, options)
// Register webpack plugin to emit icons
this.extendBuild((config, { isClient }) => {
if (isClient) {
config.plugins.push({
apply (compiler) {
compiler.hooks.emit.tapPromise('nuxt-pwa-icon', async compilation => {
await resizePromise
await Promise.all(options.sizes.map(async size => {
const targetFilename = options._icons[size]
const srcFileName = path.join(options._cacheDir, `${size}.png`)
const src = await fs.readFile(srcFileName)
compilation.assets[targetFilename] = { source: () => src, size: () => src.length }
}))
})
}
})
}
})
}
async function resizeIcons (options) {
if (await fs.exists(options._cacheDir)) {
return
}
await fs.mkdirp(options._cacheDir)
await new Promise((resolve, reject) => {
const child = fork(require.resolve('./resize'), [
JSON.stringify({
input: options.iconSrc,
distDir: options._cacheDir,
sizes: options.sizes
})
])
child.on('exit', (code) => {
return code ? reject(code) : resolve()
})
})
}
module.exports.meta = require('./package.json')