Skip to content

Commit

Permalink
webpack 5
Browse files Browse the repository at this point in the history
  • Loading branch information
dzuloaga committed Dec 2, 2021
2 parents 0006109 + d8f060c commit 8ef0816
Show file tree
Hide file tree
Showing 32 changed files with 17,365 additions and 9,809 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"@babel/preset-env",
{
"targets": {
"node": "10.13.0"
"node": "12.22.1"
}
}
]
Expand Down
24,667 changes: 16,415 additions & 8,252 deletions package-lock.json

Large diffs are not rendered by default.

52 changes: 26 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
"description": "A webpack loader for responsive images",
"main": "lib/cjs.js",
"engines": {
"node": ">= 10.13.0"
"node": ">= 12.22.1"
},
"scripts": {
"build": "tsc && cp ./src/cjs.js ./lib",
"lint": "eslint",
"test:clean": "find test/**/build/ -name '*.jpg' -o -name '*.png' -o -name '*.avif' -o -name '*.webp' -o -name '*.js' | xargs rm -f",
"test": "npm run build && npm run test:clean && webpack --config=./test/jimp/webpack.config.js && webpack --config=./test/sharp/webpack.config.js && webpack --config=./test/cache/webpack.config.js && jest"
"test:clean": "find test/**/build/ -name '*.jpg' -o -name '*.png' -o -name '*.avif' -o -name '*.wep' -o -name '*.js' | xargs rm -f",
"test": "npm run build && npm run test:clean && webpack --config=./test/jimp/webpack.config.js && webpack --config=./test/sharp/webpack.config.js && jest"
},
"files": [
"lib",
Expand All @@ -37,7 +37,7 @@
},
"homepage": "https://github.com/dazuaz/responsive-loader",
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
"webpack": "^5.38.1"
},
"peerDependenciesMeta": {
"jimp": {
Expand All @@ -48,31 +48,31 @@
}
},
"dependencies": {
"find-cache-dir": "^3.3.1",
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
"@types/node": "^14.17.34",
"find-cache-dir": "^3.3.2",
"json5": "^2.2.0",
"schema-utils": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@types/find-cache-dir": "^3.2.0",
"@types/json-schema": "^7.0.6",
"@types/loader-utils": "^2.0.1",
"@types/node": "^14.14.20",
"@types/sharp": "^0.27.0",
"@types/webpack": "^4.41.25",
"@typescript-eslint/eslint-plugin": "^4.12.0",
"@typescript-eslint/parser": "^4.12.0",
"babel-jest": "^26.6.3",
"eslint": "^7.17.0",
"jest": "^26.6.3",
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.4",
"@types/find-cache-dir": "^3.2.1",
"@types/jest": "^27.0.3",
"@types/json-schema": "^7.0.9",
"@types/sharp": "^0.29.4",
"@types/webpack": "^5.28.0",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"babel-jest": "^27.4.2",
"eslint": "^8.3.0",
"jest": "^27.4.3",
"jimp": "^0.16.1",
"prettier": "^2.2.1",
"prettier-eslint": "^12.0.0",
"sharp": "^0.27.0",
"typescript": "^4.1.3",
"webpack": "^4.44.2",
"webpack-cli": "^4.3.1"
"prettier": "^2.5.0",
"prettier-eslint": "^13.0.0",
"sharp": "^0.29.3",
"typescript": "^4.5.2",
"webpack": "^5.64.4",
"webpack-cli": "^4.9.1"
},
"jest": {
"testEnvironment": "node"
Expand Down
15 changes: 7 additions & 8 deletions src/adapters/sharp.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as sharp from "sharp"
import * as sharp from 'sharp'

type ResizeProps = {
width: number
mime: "image/jpeg" | "image/png" | "image/webp" | "image/avif"
mime: 'image/jpeg' | 'image/png' | 'image/webp' | 'image/avif'
options: {
background?: string
rotate: number
Expand All @@ -13,7 +13,7 @@ type ResizeProps = {

class SharpAdapter {
image: sharp.Sharp
constructor(imagePath: string | Buffer) {
constructor(imagePath: string) {
this.image = sharp(imagePath)
}
metadata(): Promise<sharp.Metadata> {
Expand All @@ -34,18 +34,18 @@ class SharpAdapter {
})
}

if (mime === "image/jpeg") {
if (mime === 'image/jpeg') {
resized = resized.jpeg({
quality: options.quality,
progressive: options.progressive,
})
}
if (mime === "image/webp") {
if (mime === 'image/webp') {
resized = resized.webp({
quality: options.quality,
})
}
if (mime === "image/avif") {
if (mime === 'image/avif') {
// @ts-ignore
resized = resized.avif({
quality: options.quality,
Expand All @@ -55,7 +55,6 @@ class SharpAdapter {
if (options.rotate && options.rotate !== 0) {
resized = resized.rotate(options.rotate)
}

resized.toBuffer((err, data, { height }) => {
if (err) {
reject(err)
Expand All @@ -71,6 +70,6 @@ class SharpAdapter {
}
}
// export default SharpAdapter
module.exports = (imagePath: string | Buffer): SharpAdapter => {
module.exports = (imagePath: string): SharpAdapter => {
return new SharpAdapter(imagePath)
}
2 changes: 1 addition & 1 deletion src/cjs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const loader = require("./index")
const loader = require('./index')

module.exports = loader.default
module.exports.raw = loader.raw
65 changes: 28 additions & 37 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { parseQuery, getOptions, interpolateName } from 'loader-utils'
import { validate } from 'schema-utils'
import * as schema from './schema.json'
import { validate } from 'schema-utils'
import { JSONSchema7 } from 'schema-utils/declarations/ValidationError'

import { parseOptions, getOutputAndPublicPath, createPlaceholder } from './utils'
import { cache } from './cache'
import type { LoaderContext } from 'webpack'

import interpolateName from './interpolateName'
import { parseQuery } from './parseQuery'

import type {
Adapter,
Options,
CacheOptions,
LoaderContext,
AdapterImplementation,
MimeType,
AdapterResizeResponse,
Expand Down Expand Up @@ -39,47 +43,36 @@ const DEFAULTS = {
*
* @return {loaderCallback} loaderCallback Result
*/
export default function loader(this: LoaderContext, content: Buffer): void {
export default function loader(this: LoaderContext<Options>, content: string): void {
const loaderCallback = this.async()
if (typeof loaderCallback == 'undefined') {
new Error('Responsive loader callback error')
return
}

// Object representation of the query string
// Parsers the query string and options
const parsedResourceQuery = this.resourceQuery ? parseQuery(this.resourceQuery) : {}

// Combines defaults, webpack options and query options,
// later sources' properties overwrite earlier ones.
const options: Options = Object.assign({}, DEFAULTS, getOptions(this), parsedResourceQuery)
const options = { ...DEFAULTS, ...this.getOptions(), ...parsedResourceQuery }

// @ts-ignore
validate(schema, options, { name: 'Responsive Loader' })
validate(schema as JSONSchema7, options, { name: 'Responsive Loader' })

/**
* Parses options and set defaults options
*/
const {
outputContext,
mime,
ext,
name,
sizes,
outputPlaceholder,
placeholderSize,
imageOptions,
cacheOptions,
} = parseOptions(this, options)
const outputContext = options.context || this.rootContext
const { mime, ext, name, sizes, outputPlaceholder, placeholderSize, imageOptions, cacheOptions } = parseOptions(
this.resourcePath,
options
)

if (!mime) {
loaderCallback(new Error('No mime type for file with extension ' + ext + ' supported'))
return
}

const createFile = ({ data, width, height }: AdapterResizeResponse) => {
const fileName = interpolateName(this, name, {
const fileName = interpolateName(this.resourcePath, this.resourceQuery, name, {
context: outputContext,
content: data,
content: data.toString(),
})
.replace(/\[width\]/gi, width + '')
.replace(/\[height\]/gi, height + '')
Expand All @@ -90,7 +83,7 @@ export default function loader(this: LoaderContext, content: Buffer): void {
})

if (options.emitFile) {
this.emitFile(outputPath, data, null)
this.emitFile(outputPath, data)
}

return {
Expand All @@ -113,16 +106,14 @@ export default function loader(this: LoaderContext, content: Buffer): void {
images: [{path:${path},width:100,height:100}],
src: ${path},
toString: function(){return ${path}}
};`
}`
)
return
}
/**
* The full config is passed to the adapter, later sources' properties overwrite earlier ones.
*/
// The full config is passed to the adapter, later sources' properties overwrite earlier ones.
const adapterOptions = Object.assign({}, options, imageOptions)

const transformParams: TransformParams = {
const transformParams = {
adapterModule: options.adapter,
resourcePath: this.resourcePath,
adapterOptions,
Expand Down Expand Up @@ -158,8 +149,8 @@ async function orchestrate(params: OrchestrateParams) {
// Transform based on the parameters
export async function transform({
adapterModule,
createFile,
resourcePath,
createFile,
sizes,
mime,
outputPlaceholder,
Expand All @@ -183,16 +174,16 @@ export async function transform({

const srcset = files.map((f) => f.src).join('+","+')
const images = files.map((f) => `{path: ${f.path},width: ${f.width},height: ${f.height}}`).join(',')
const firstImage = files[0]
const defaultImage = outputPlaceholder ? files[files.length - 2] : files[files.length - 1]

return `${esModule ? 'export default' : 'module.exports ='} {
srcSet: ${srcset},
images: [${images}],
src: ${firstImage.path},
toString: function(){return ${firstImage.path}},
src: ${defaultImage.path},
toString: function(){return ${defaultImage.path}},
${placeholder ? 'placeholder: ' + placeholder + ',' : ''}
width: ${firstImage.width},
height: ${firstImage.height}
width: ${defaultImage.width},
height: ${defaultImage.height}
}`
}

Expand Down
88 changes: 88 additions & 0 deletions src/interpolateName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use strict'

import { util } from 'webpack'
import * as path from 'path'

type Options = {
context: string
content: string
}

export default function interpolateName(
loaderResourcePath: string,
loaderResourceQuery: string,
name: string,
options: Options
): string {
const filename = name || '[hash].[ext]'

const context = options.context
const content = options.content

let ext = 'bin'
let basename = 'file'
let directory = ''
let folder = ''
let query = ''

if (loaderResourcePath) {
const parsed = path.parse(loaderResourcePath)
let resourcePath = loaderResourcePath

if (parsed.ext) {
ext = parsed.ext.substr(1)
}

if (parsed.dir) {
basename = parsed.name
resourcePath = parsed.dir + path.sep
}

if (typeof context !== 'undefined') {
directory = path
.relative(context, resourcePath + '_')
.replace(/\\/g, '/')
.replace(/\.\.(\/)?/g, '_$1')
directory = directory.substr(0, directory.length - 1)
} else {
directory = resourcePath.replace(/\\/g, '/').replace(/\.\.(\/)?/g, '_$1')
}

if (directory.length === 1) {
directory = ''
} else if (directory.length > 1) {
folder = path.basename(directory)
}
}

if (loaderResourceQuery && loaderResourceQuery.length > 1) {
query = loaderResourceQuery

const hashIdx = query.indexOf('#')

if (hashIdx >= 0) {
query = query.substr(0, hashIdx)
}
}

let url = filename

if (content) {
const hash = util.createHash('md4')
hash.update(content)
// Match hash template
url = url
// `hash` and `contenthash` are same in `loader-utils` context
// let's keep `hash` for backward compatibility
.replace(/\[(?:([^:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi, `${hash.digest('hex')}`)
}

url = url
.replace(/\[ext\]/gi, () => ext)
.replace(/\[name\]/gi, () => basename)
.replace(/\[path\]/gi, () => directory)
.replace(/\[folder\]/gi, () => folder)
.replace(/\[query\]/gi, () => query)

return url
}
Loading

0 comments on commit 8ef0816

Please sign in to comment.