mixtur / webpack-spritesmith

Webpack plugin that converts set of images into a spritesheet and SASS/LESS/Stylus mixins
498 stars 56 forks source link

Multiple customTemplates functions #87

Closed GreenMashimaro closed 4 years ago

GreenMashimaro commented 4 years ago

Hello, I saw the same problem in the issue, but it was not resolved, but I feel it is necessary to support this feature.

50

I need to generate 2 sprites based on two different directories. But these two sprites are different templates. Problem: The problem is that the template for the second new SpritesmithPlugin will overwrite the template for the first new SpritesmithPlugin.

plugins: [
  new SpritesmithPlugin({
    customTemplates: {
      icon_template: function (data) {
        var shared = '.ico { background-image: url(I) }'
            .replace('I', data.sprites[0].image);

        var perSprite = data.sprites.map(function (sprite) {
          return '.ico-N { width: Wpx; height: Hpx; background-position: Xpx Ypx; }'
              .replace('N', sprite.name)
              .replace('W', sprite.width)
              .replace('H', sprite.height)
              .replace('X', sprite.offset_x)
              .replace('Y', sprite.offset_y);
        }).join('\n');

        return shared + '\n' + perSprite;
      }
    }
  }),
  new SpritesmithPlugin({
    customTemplates: {
      icon_template: function (data) {
        var shared = '.ico { background-image: url(I) }'
            .replace('I', data.sprites[0].image);

        var perSprite = data.sprites.map(function (sprite) {
          return '.ico-N { width: WPX; height: HPX; background-position: XPX YPX; }'
              .replace('N', sprite.name)
              .replace('W', sprite.width)
              .replace('H', sprite.height)
              .replace('X', sprite.offset_x)
              .replace('Y', sprite.offset_y);
        }).join('\n');

        return shared + '\n' + perSprite;
      }
    }
  })
]

Please note that the second template is that px is uppercase.This is just to demonstrate the need for different templates.

mixtur commented 4 years ago

I would suggest using different name. icon_template_2 for instance. Plugin could do this automatically but now it doesn't. Maybe I'll add this automation. Though if people relied on current behaviour, it would be a breaking change.

mixtur commented 4 years ago

Globality of the namespace comes from the way, spritesheet-templates is designed. It registers custom templates globally and you can't unregister it afterward. So I can't do it "truly" local. Unless I'll use different template library.

GreenMashimaro commented 4 years ago

Thank you for your reply!

"I would suggest using different name. icon_template_2 for instance. Plugin could do this automatically but now it doesn't. " But this way, not very friendly.

The following are the scenarios that are more likely to be used at work. example:

const spritesmithTpl = function (data, iconClsName) {
  if (!data) return

  if (!data.sprites.length) return

  let shared = `${iconClsName} { background-image: url(I); }`.replace('I', data.sprites[0].image)
  let perSprite = data.sprites.map(function (sprite) {
    return `.${sprite.name} { display:inline-block; width: ${sprite.width}px; height: ${sprite.height}px;
      vertical-align: top; background-repeat: no-repeat; background-position: ${sprite.offset_x}px ${sprite.offset_y}px;
      background-size: ${sprite.total_width}px ${sprite.total_height}px; }`
  }).join('\n')

  return `${shared}\n${perSprite}`
}

const getSpriteConfig = (name = 'icon') => {
  return {
    src: {
      cwd: `./src/assets/images/${name}`,
      glob: 'icon_*.{jpg,png}'
    },
    target: {
      image: `./src/assets/images/${name}/sprite.png`,
      css: [
        [`./src/assets/scss/${name}.scss`, { format: 'icon_template' }]
      ]
    },
    apiOptions: {
      cssImageRef: `~@/assets/images/${name}/sprite.png`
    },
    customTemplates: {
      icon_template: function (data) {
        return spritesmithTpl(data, `.${name}`)
      }
    }
  }
}

// webpack.config.js
plugins: [
  new SpritesmithPlugin(getSpriteConfig('icon')),
  new SpritesmithPlugin(getSpriteConfig('sm_icon'))
]

If the template uses two different names, it will be difficult for the later maintainers to understand the logic.

In summary, if there is no better way to solve it, I can accept the use of two different template names.

GreenMashimaro commented 4 years ago

Hello, I found a solution to the problem. Modify customTemplates to iife function.

const spritesmithTpl = function (data, iconClsName) {
  if (!data) return

  if (!data.sprites.length) return

  let shared = `${iconClsName} { background-image: url(I); }`.replace('I', data.sprites[0].image)
  let perSprite = data.sprites.map(function (sprite) {
    return `.${sprite.name} { display:inline-block; width: ${sprite.width}px; height: ${sprite.height}px;
      vertical-align: top; background-repeat: no-repeat; background-position: ${sprite.offset_x}px ${sprite.offset_y}px;
      background-size: ${sprite.total_width}px ${sprite.total_height}px; }`
  }).join('\n')

  return `${shared}\n${perSprite}`
}

const getSpriteConfig = (name = 'icon') => {
  let formatName = `${name}_template`
  return {
    src: {
      cwd: `./src/assets/images/${name}`,
      glob: 'icon_*.{jpg,png}'
    },
    target: {
      image: `./src/assets/images/${name}/sprite.png`,
      css: [
        [`./src/assets/scss/${name}.scss`, { format: formatName }]
      ]
    },
    apiOptions: {
      cssImageRef: `~@/assets/images/${name}/sprite.png`
    },
    customTemplates: {
      [formatName]: function (data) {
        return spritesmithTpl(data, `.${name}`)
      }
    }
  }
}

// webpack.config.js
plugins: [
  new SpritesmithPlugin(getSpriteConfig('icon')),
  new SpritesmithPlugin(getSpriteConfig('sm_icon'))
]
mixtur commented 4 years ago

btw with modern js (Node 12, I think) you can do

customTemplates: {
  [formatName]: data => spritesmithTpl(data, '.' + name)
}

So you don't need iife in your case

Yet I think it would be better if plugin could avoid this problem by itself. Uh... I wish I had more hours in a day) I hope to do it some time later

GreenMashimaro commented 4 years ago

Thank you very much for your suggestion, the demo of the above demo has been updated.