@vitbokisch/next-optimized-images
Version:
Automatically optimize images used in next.js projects (jpeg, png, gif, svg).
186 lines (167 loc) • 4.47 kB
JavaScript
import { createRequire } from 'module'
import { getUrlLoaderOptions } from './loaders/url-loader.js'
import {
getFileLoaderOptions,
getFileLoaderPath,
} from './loaders/file-loader.js'
import { getLqipLoaderOptions } from './loaders/lqip-loader/index.js'
import { getResponsiveLoaderOptions } from './loaders/responsive-loader.js'
import { getImageTraceLoaderOptions } from './loaders/image-trace-loader.js'
const require = createRequire(import.meta.url)
/**
* Configure the common resource queries
*/
const queries = [
// ?url: force a file url/reference, never use inlining
{
test: 'url',
loaders: [getFileLoaderPath()],
optimize: true,
combinations: ['original'],
},
// ?inline: force inlining an image regardless of the defined limit
{
test: 'inline',
loaders: ['url-loader'],
options: [
{
limit: undefined,
},
],
optimize: true,
combinations: ['original'],
},
// ?include: include the image directly, no data uri or external file
{
test: 'include',
loaders: [
require.resolve('./loaders/raw-loader/export-loader.js'),
'raw-loader',
],
optimize: true,
combinations: ['original'],
},
// ?original: use the original image and don't optimize it
{
test: 'original',
loaders: ['url-loader'],
optimize: false,
},
// ?lqip: low quality image placeholder
{
test: 'lqip(&|$)',
loaders: [
require.resolve('./loaders/lqip-loader/picture-export-loader.js'),
'lqip-loader',
'url-loader',
],
optimize: false,
},
// ?lqip: low quality image placeholder
{
test: 'lqip-colors',
loaders: [
require.resolve('./loaders/lqip-loader/colors-export-loader.js'),
'lqip-loader',
'url-loader',
],
options: [
{},
{
base64: false,
palette: true,
},
],
optimize: false,
},
// ?resize: resize images
{
test: 'size',
loaders: ['responsive-loader'],
optimize: false,
},
// ?trace: generate svg image traces for placeholders
{
test: 'trace',
loaders: ['image-trace-loader', 'url-loader'],
optimize: true,
combinations: ['original'],
},
]
/**
* Add combinations
*/
;[].concat(queries).forEach((queryConfig) => {
if (queryConfig.combinations) {
queryConfig.combinations.forEach((combination) => {
if (combination === 'original') {
queries.unshift({
...queryConfig,
test: `(${queryConfig.test}.*original|original.*${queryConfig.test})`,
optimize: false,
})
}
})
}
})
/**
* Returns all common resource queries for the given optimization loader
*
* @param {object} nextConfig - next.js configuration object
* @param {boolean} isServer - if the current build is for a server
* @param {string} optimizerLoaderName - name of the loader used to optimize the images
* @param {object} optimizerLoaderOptions - config for the optimization loader
* @returns {array}
*/
const getResourceQueries = (
nextConfig,
isServer,
optimizerLoaderName,
optimizerLoaderOptions,
detectLoaders
) => {
const loaderOptions = {
'url-loader': getUrlLoaderOptions(nextConfig, isServer),
'file-loader': getFileLoaderOptions(nextConfig, isServer),
[getFileLoaderPath()]: getFileLoaderOptions(nextConfig, isServer),
'lqip-loader': getLqipLoaderOptions(nextConfig, isServer),
'responsive-loader': getResponsiveLoaderOptions(
nextConfig,
isServer,
detectLoaders
),
'image-trace-loader': getImageTraceLoaderOptions(nextConfig),
}
return queries.map((queryConfig) => {
const loaders = []
queryConfig.loaders.forEach((loader, index) => {
const loaderConfig = {
loader,
}
if (loaderOptions[loader]) {
loaderConfig.options = loaderOptions[loader]
}
if (queryConfig.options) {
loaderConfig.options = {
...(loaderConfig.options || {}),
...(queryConfig.options[index] || {}),
}
}
loaders.push(loaderConfig)
})
return {
resourceQuery: new RegExp(queryConfig.test),
use: loaders.concat(
queryConfig.optimize && optimizerLoaderName !== null
? [
{
loader: optimizerLoaderName,
options: optimizerLoaderOptions,
},
]
: []
),
}
})
}
export { getResourceQueries }