grunt-sharp-optimize

Форк
0
180 строк · 5.1 Кб
1
'use strict'
2

3
const sharp = require('sharp'),
4
  globParent = require('glob-parent'),
5
  fs = require('fs-extra'),
6
  path = require('path')
7

8
const
9
  ALLOWED_EXTENSIONS = [
10
    'gif',
11
    'png',
12
    'jpg', 'jpeg',
13
    'webp',
14
    'avif',
15
    'tiff',
16
    'heif',
17
  ],
18
  DEFAULT_CONVERSION_OPTIONS = {
19
    quality: 90,
20
    lossless: false,
21
    chromaSubsampling: '4:2:0',
22
  },
23
  DEFAULT_SHARP_OPTIONS = {
24
    animated: true,
25
    limitInputPixels: false,
26
  }
27

28
let logLevel, sharpOptions, destCwd, sourceCwd
29
var chalk
30

31
module.exports = function (grunt) {
32
  grunt.task.registerMultiTask('sharp', 'Convert and optimize images with Sharp.',
33
    async function () {
34
      let
35
        done = this.async(),
36
        options = this.options()
37

38
      chalk = await getChalkModule()
39

40
      logLevel = options.logLevel ?? 'small'
41
      sharpOptions = options.sharpOptions ?? {}
42
      destCwd = this.files[0].dest
43
      sourceCwd = globParent(this.data.src)
44

45
      delete options.logLevel
46
      delete options.sharpOptions
47

48

49
      for (let fileSrc of this.filesSrc) {
50
        let
51
          parsedFile = path.parse(fileSrc),
52
          fileExtname = parsedFile.ext.replace('.', ''),
53
          fileName = parsedFile.name,
54
          fileBase = parsedFile.base,
55
          fileCwd = parsedFile.dir.replace(sourceCwd, ''),
56

57
          pathToDist = createPathToNewFileInDist(fileName, fileExtname, fileCwd)
58

59
        fs.ensureDirSync(pathToDist.replace(parsedFile.base, ''))
60

61
        if (!extnamesIsCorrect(fileExtname)) {
62
          if (fs.existsSync(pathToDist)) continue
63

64
          fs.copySync(fileSrc, pathToDist)
65

66
          logAboutSuccessfulCopy(fileBase)
67
          continue
68
        }
69

70
        for (let [conversionRule, conversionRuleOptions] of Object.entries(options)) {
71
          let [convertFrom, convertTo] = conversionRule.split('_to_')
72

73
          if (!extnamesIsCorrect(convertFrom, convertTo)) {
74
            console.error(chalk.red.bold('Invalid name of an conversion rule! Make sure you have spelled the extension names correctly.'))
75

76
            return done(false)
77
          }
78

79

80
          // Checking that the file has not a suitable extension
81
          if (convertTo && convertFrom != fileExtname) continue
82

83
          //? For general conversion rules such as png: {}
84
          if (!convertTo) {
85
            let newFilePath = createPathToNewFileInDist(fileName, convertFrom, fileCwd)
86

87
            // Checking that the file has already been created
88
            if (fs.existsSync(newFilePath)) continue
89

90
            await convert(fileSrc, convertFrom, conversionRuleOptions, newFilePath)
91
            logAboutSuccessfulConversion(fileBase, fileName, convertFrom)
92

93
            if (conversionRuleOptions.alsoProcessOriginal) {
94
              let newFilePath = createPathToNewFileInDist(fileName, fileExtname, fileCwd)
95

96
              if (fs.existsSync(newFilePath)) continue
97

98
              await convert(fileSrc, fileExtname, conversionRuleOptions, newFilePath)
99
              logAboutSuccessfulConversion(fileBase, fileName, fileExtname)
100
            }
101
          }
102
          //? For specific conversion rules such as png_to_webp: {}
103
          else {
104
            let newFilePath = createPathToNewFileInDist(fileName, convertTo, fileCwd)
105

106
            if (fs.existsSync(newFilePath)) continue
107

108
            await convert(fileSrc, convertFrom, convertTo, conversionRuleOptions, newFilePath)
109
            logAboutSuccessfulConversion(fileBase, fileName, convertTo)
110
          }
111
        }
112
      }
113

114
      return done(true)
115
    }
116
  )
117

118
  async function convert(filePath, oldFileFormat, newFileFormat, options, newFilePath) {
119
    if (newFileFormat == 'heif' && !options.compression)
120
      options.compression = 'av1'
121
    else if (oldFileFormat == 'heif' && !options.compression)
122
      options.compression = 'jpeg'
123

124
    let sharpInstance =
125
      await sharp(filePath, Object.assign(DEFAULT_SHARP_OPTIONS, sharpOptions))
126
        .toFormat(newFileFormat, Object.assign(DEFAULT_CONVERSION_OPTIONS, options))
127

128
    fs.createFileSync(newFilePath)
129

130
    await sharpInstance.toFile(newFilePath)
131
  }
132
}
133

134
function logAboutSuccessfulConversion(fileBase, fileName, newFileExtname) {
135
  if (logLevel == 'full')
136
    console.log(
137
      'The file ' + chalk.green(sourceCwd + fileBase)
138
      + ' was processed to '
139
      + chalk.green(destCwd + fileName + '.' + chalk.bold(newFileExtname))
140
    )
141
  else if (logLevel == 'small')
142
    console.log(
143
      chalk.green(fileBase) + ' => ' + chalk.green.bold(newFileExtname)
144
    )
145
}
146
function logAboutSuccessfulCopy(fileBase) {
147
  if (logLevel == 'full')
148
    console.log(chalk.hex('#FF8800')
149
      (
150
        `The image ${chalk.bold(fileBase)} cannot be processed, so it is copied to dest.`
151
      )
152
    )
153
  else if (logLevel == 'small')
154
    console.log(chalk.hex('#FF8800')
155
      (fileBase + ' => ' + chalk.bold('copied'))
156
    )
157
}
158

159
function createPathToNewFileInDist(fileName, newFileExt, fileCwd) {
160
  return path.resolve(`${destCwd}/${fileCwd}/${fileName}.${newFileExt}`)
161
}
162

163
function extnamesIsCorrect(...extnames) {
164
  for (let extname of extnames) {
165
    if (!ALLOWED_EXTENSIONS.includes(extname)) {
166
      return false
167
    }
168
  }
169

170
  return true
171
}
172

173
async function getChalkModule() {
174
  if (!chalk) {
175
    return (await import('chalk')).default
176
  }
177
  else {
178
    return chalk
179
  }
180
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.