Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't require from component #209

Open
JuanM04 opened this issue Sep 25, 2020 · 1 comment
Open

Can't require from component #209

JuanM04 opened this issue Sep 25, 2020 · 1 comment

Comments

@JuanM04
Copy link

JuanM04 commented Sep 25, 2020

When I require an image from /pages, it works perfectly; but when I do it from /components, it throws "Can't find module [path]".

Next version: 9.5.3
Next-optimized-images version: 2.6.2
Typescript version: 4.0.2

@DmitryKvant
Copy link

You need to use babel compiler for replace param of image at the place of the component call

babel-plugin-replace-path-images.js

var babelParser = require('@babel/parser')

const nestedVisitor = {
    StringLiteral(path, opts) {
      try{
      
      var pathFile = path.node.value;

      if(pathFile && /\_\_load\_images\_\_/g.test(pathFile)){

        console.log('optimize image', pathFile)

        var newPath = pathFile.replace('__load_images__', ''),
            originPath = newPath;

        var pathRequest = newPath.match(/\?.*/g);

        if(pathRequest){
            pathRequest = pathRequest[0];
            newPath = newPath.replace(pathRequest, '')
        }

        if( !newPath ) return match;

        var resizeMode = pathRequest && /\\?resize/.test(pathRequest),
            webpMode = pathRequest && /\\?webp/.test(pathRequest),
            images = [], imagesString = '[';

        if(resizeMode){
          images.push(`require('public/static/${newPath}?resize&format=webp')`)

          if(/\.png/g.test(newPath)){
              images.push(`require('public/static/${newPath}?resize&format=png')`);
          }

          if(/\.jpg/g.test(newPath)){
              images.push(`require('public/static/${newPath}?resize&format=jpg')`);
          }
        }


        if(webpMode){
            images.push(`{path: require('public/static/${newPath}?webp')}`)
            images.push(`{path: require('public/static/${newPath}')}`)
        }

        if(!webpMode && !resizeMode){
          images.push(`{path: require('public/static/${originPath}')}`)
        }

        for(var item of images){
          imagesString += item + ','
        }

        imagesString += ']';

        var node = babelParser.parse(imagesString)

        path.replaceWith(
          node.program.body[0]
        );
        
    }

    }catch(err){
      console.log('err', err)
    }
  }

}

const nestedVisitor2 = {
  JSXExpressionContainer(path, opts){
    path.traverse(nestedVisitor, opts);
  }
}

module.exports = function({ types: t }) {
  return {
    visitor: {
      JSXAttribute(path) {

        path.traverse(nestedVisitor2, t);

      }
    }
  };
}

then apply plugin in babel.config.js

require('dotenv').config();

var DEV_VAR = process.env.DEV_VAR == 'true' ? false : true;

module.exports = function (api) {
  api.cache(DEV_VAR);

  return {
    presets: [
      ["next/babel"]
    ],
    "plugins": [
      ["./babel-plugin-replace-path-images.js"]
    ]
  }
}

It also works correctly on devices that do not support the webp image format.

My realization of image wrapper component -

import { Component } from 'react';
class Img extends Component {
    componentDidMount() {
        if (this.img.complete) {
            this.img.style.background = 'initial';
        }
    }
    render() {
        return(
            <img
                ref={el => this.img = el}

                onLoad={ e => {
                    e.target.style.background = 'initial'
                }}

                {...this.props}
            />
        )
    }
}

const Image = (props) => {

    if(!props.src) return null;

    var newProps = JSON.parse(JSON.stringify(props))

    var images = [], image, placeholder, addExtra = false;

    for(var item of props.src){
        if(item.images){
            if(!addExtra){
                addExtra = true;
                image = item.image;
                placeholder = item.placeholder;
            }
            for(var item2 of item.images){
                images.push(item2)
            }
        }else{
            images.push(item)
        }
    }

    var reversed = images.reverse();

    delete newProps.src;
    delete newProps.require;
    delete newProps.priority;

    if(placeholder){
        newProps.style = {background: `url(${placeholder})`}
    }

    if(!props.priority){
        newProps.loading = "lazy"
    }

    return(
        <picture>
            {reversed.map(item => {
                var sourceProps = {
                    srcSet: item.path,
                    type: 'image/'
                }

                if(/(\.png|data\:image\/png\;base64)/g.test(item.path)){
                    sourceProps.type += 'png'
                }else if(/(\.webp|data\:image\/webp\;base64)/g.test(item.path)){
                    sourceProps.type += 'webp'
                }else if(/(\.jpg|data\:image\/jpg\;base64)/g.test(item.path)){
                    sourceProps.type += 'jpeg'
                }else{
                   delete sourceProps.type;
                }

                if(item.width){
                    sourceProps.media = `(min-width: ${item.width - 10}px)`
                }
                return(
                    <source {...sourceProps} />
                )
            })}

            <Img
                src={image}
                {...newProps}
            />
        </picture>
    )
};

export default Image;

finally example how you can use it

<Image draggable="false" src={"__load_images__happyDeveloper.png?resize"}  alt="Счастливый разработчик" />
```You need to use babel compiler for replace param of image at the place of the component call

> babel-plugin-replace-path-images.js

```JavaScript
var babelParser = require('@babel/parser')

const nestedVisitor = {
    StringLiteral(path, opts) {
      try{
      
      var pathFile = path.node.value;

      if(pathFile && /\_\_load\_images\_\_/g.test(pathFile)){

        console.log('optimize image', pathFile)

        var newPath = pathFile.replace('__load_images__', ''),
            originPath = newPath;

        var pathRequest = newPath.match(/\?.*/g);

        if(pathRequest){
            pathRequest = pathRequest[0];
            newPath = newPath.replace(pathRequest, '')
        }

        if( !newPath ) return match;

        var resizeMode = pathRequest && /\\?resize/.test(pathRequest),
            webpMode = pathRequest && /\\?webp/.test(pathRequest),
            images = [], imagesString = '[';

        if(resizeMode){
          images.push(`require('public/static/${newPath}?resize&format=webp')`)

          if(/\.png/g.test(newPath)){
              images.push(`require('public/static/${newPath}?resize&format=png')`);
          }

          if(/\.jpg/g.test(newPath)){
              images.push(`require('public/static/${newPath}?resize&format=jpg')`);
          }
        }


        if(webpMode){
            images.push(`{path: require('public/static/${newPath}?webp')}`)
            images.push(`{path: require('public/static/${newPath}')}`)
        }

        if(!webpMode && !resizeMode){
          images.push(`{path: require('public/static/${originPath}')}`)
        }

        for(var item of images){
          imagesString += item + ','
        }

        imagesString += ']';

        var node = babelParser.parse(imagesString)

        path.replaceWith(
          node.program.body[0]
        );
        
    }

    }catch(err){
      console.log('err', err)
    }
  }

}

const nestedVisitor2 = {
  JSXExpressionContainer(path, opts){
    path.traverse(nestedVisitor, opts);
  }
}

module.exports = function({ types: t }) {
  return {
    visitor: {
      JSXAttribute(path) {

        path.traverse(nestedVisitor2, t);

      }
    }
  };
}

then apply plugin in babel.config.js

require('dotenv').config();

var DEV_VAR = process.env.DEV_VAR == 'true' ? false : true;

module.exports = function (api) {
  api.cache(DEV_VAR);

  return {
    presets: [
      ["next/babel"]
    ],
    "plugins": [
      ["./babel-plugin-replace-path-images.js"]
    ]
  }
}

It also works correctly on devices that do not support the webp image format.

My realization of image wrapper component -

import { Component } from 'react';
class Img extends Component {
    componentDidMount() {
        if (this.img.complete) {
            this.img.style.background = 'initial';
        }
    }
    render() {
        return(
            <img
                ref={el => this.img = el}

                onLoad={ e => {
                    e.target.style.background = 'initial'
                }}

                {...this.props}
            />
        )
    }
}

const Image = (props) => {

    if(!props.src) return null;

    var newProps = JSON.parse(JSON.stringify(props))

    var images = [], image, placeholder, addExtra = false;

    for(var item of props.src){
        if(item.images){
            if(!addExtra){
                addExtra = true;
                image = item.image;
                placeholder = item.placeholder;
            }
            for(var item2 of item.images){
                images.push(item2)
            }
        }else{
            images.push(item)
        }
    }

    var reversed = images.reverse();

    delete newProps.src;
    delete newProps.require;
    delete newProps.priority;

    if(placeholder){
        newProps.style = {background: `url(${placeholder})`}
    }

    if(!props.priority){
        newProps.loading = "lazy"
    }

    return(
        <picture>
            {reversed.map(item => {
                var sourceProps = {
                    srcSet: item.path,
                    type: 'image/'
                }

                if(/(\.png|data\:image\/png\;base64)/g.test(item.path)){
                    sourceProps.type += 'png'
                }else if(/(\.webp|data\:image\/webp\;base64)/g.test(item.path)){
                    sourceProps.type += 'webp'
                }else if(/(\.jpg|data\:image\/jpg\;base64)/g.test(item.path)){
                    sourceProps.type += 'jpeg'
                }else{
                   delete sourceProps.type;
                }

                if(item.width){
                    sourceProps.media = `(min-width: ${item.width - 10}px)`
                }
                return(
                    <source {...sourceProps} />
                )
            })}

            <Img
                src={image}
                {...newProps}
            />
        </picture>
    )
};

export default Image;

finally example how you can use it

<Image draggable="false" src={"__load_images__happyDeveloper.png?resize"}  alt="Счастливый разработчик" />

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants