Gatsby: Can't dynamic require img?

Created on 17 Jul 2017  ·  3Comments  ·  Source: gatsbyjs/gatsby

hello, I am writing a blog and in the posts index I want to list all my posts and each post has a cover.
below is my code:

 {posts.map(post => {
            return <li key={post.node.fields.slug}>
              <Link to={post.node.fields.slug}>
                <img className="news-img" src={require(`../${post.node.frontmatter.cover.relativePath}`)} />
                <h3 className="news-titles">{post.node.frontmatter.title}</h3>
                <p className="news-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{post.node.excerpt}</p>
              </Link>
            </li>
          }
          )}

but I got the warning:

 warning  in ./src/pages/md/new4/new4.md

Module parse failed: /Users/magicly/development/blog/gatsby-starter-blog/src/pages/md/new4/new4.md Assigning to rvalue (1:2)
You may need an appropriate loader to handle this file type.
SyntaxError: Assigning to rvalue (1:2)
    at Parser.pp$4.raise (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:2221:15)
    at Parser.pp$2.checkLVal (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:1509:12)
    at Parser.pp$3.parseMaybeUnary (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:1685:24)
    at Parser.pp$3.parseExprOps (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:1637:21)
    at Parser.pp$3.parseMaybeConditional (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:1620:21)
    at Parser.pp$3.parseMaybeAssign (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:1597:21)
    at Parser.pp$3.parseExpression (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:1573:21)
    at Parser.pp$1.parseStatement (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:727:47)
    at Parser.pp$1.parseTopLevel (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:638:25)
    at Parser.parse (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:516:17)
    at Object.parse (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/acorn/dist/acorn.js:3098:39)
    at Parser.parse (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/webpack/lib/Parser.js:902:15)
    at NormalModule.<anonymous> (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/webpack/lib/NormalModule.js:104:16)
    at NormalModule.onModuleBuild (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:310:10)
    at nextLoader (/Users/magicly/development/blog/gatsby-starter-blog/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:275:25)
    at /Users/magicly/development/blog/gatsby-starter-blog/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:259:5

 @ ./src/pages ^\.\/.*$

despite the warning, the page seems ok, but when I build the pages, and deploy, then got the errors:

Uncaught TypeError: Cannot read property 'call' of undefined
    at t (bootstrap 29073ca…:52)
    at Object../src/components/Footer/footer.css (footer.css:1)
    at t (bootstrap 29073ca…:52)
    at Object.<anonymous> (index.jsx:5)
    at Object../src/components/Footer/index.jsx (layout-component---index-adc8f24….js:153)
    at t (bootstrap 29073ca…:52)
    at Object.<anonymous> (index.jsx:3)
    at Object../node_modules/babel-loader/lib/index.js?{"plugins":["/Users/magicly/development/blog/gatsby-starter-blog/node_modules/gatsby/dist/utils/babel-plugin-extract-graphql.js","add-module-exports","add-module-exports","add-module-exports","transform-object-assign",["transform-react-jsx",{"pragma":"Glamor.createElement"}],"babel-plugin-glamor"],"presets":["/Users/magicly/development/blog/gatsby-starter-blog/node_modules/babel-preset-react/lib/index.js","/Users/magicly/development/blog/gatsby-starter-blog/node_modules/babel-preset-es2015/lib/index.js","/Users/magicly/development/blog/gatsby-starter-blog/node_modules/babel-preset-stage-1/lib/index.js","/Users/magicly/development/blog/gatsby-starter-blog/node_modules/babel-preset-env/lib/index.js","/Users/magicly/development/blog/gatsby-starter-blog/node_modules/babel-preset-stage-0/lib/index.js","/Users/magicly/development/blog/gatsby-starter-blog/node_modules/babel-preset-react/lib/index.js"],"cacheDirectory":true}!./src/layouts/index.jsx (layout-component---index-adc8f24….js:757)
    at t (bootstrap 29073ca…:52)
    at index.jsx?8a0a:11

Then I change my code to this:

 {posts.map(post => {
            const path = `../${post.node.frontmatter.cover.relativePath}`;
            return <li key={post.node.fields.slug}>
              <Link to={post.node.fields.slug}>
                <img className="news-img" src={require(path)} />
                <h3 className="news-titles">{post.node.frontmatter.title}</h3>
                <p className="news-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{post.node.excerpt}</p>
              </Link>
            </li>
          }
          )}

and I got the warning on the console,
``` WARNING Compiled with 1 warnings 10:31:08

warning in ./src/pages/news/index.jsx

Critical dependencies:
103:74-87 the request of a dependency is an expression

@ ./src/pages/news/index.jsx 103:74-87

and the error on web page:

Error: Cannot find module '../md/new4/cover4.png'.
http://localhost:8000/commons.js:55706:42
webpackContextResolve (webpack:/src/pages/news
^./.$:11
webpackContext (webpack:/src/pages/news
^./.
$:8
http://localhost:8000/commons.js:7945:98
Array.map
(native)
Index.render
webpack:///src/pages/news/index.jsx:21
Index.render
webpack:///~/react-proxy/modules/createPrototypeProxy.js:44
http://localhost:8000/commons.js:30838:22
measureLifeCyclePerf
webpack:///~/react-dom/lib/ReactCompositeComponent.js:75
ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext
webpack:///~/react-dom/lib/ReactCompositeComponent.js:794

I am sure the path  '../md/new4/cover4.png' is right, because if I change code to:

{posts.map(post => {
return


  • {post.node.frontmatter.title}


            {post.node.excerpt}




  • }
    )}
    ```
    then everything is fine. my environment is:
    node: v8.1.2
    npm: v5.0.3
    gatsby: 1.2.0
    OSX 10.11.5

    thanks~

    Most helpful comment

    I google

    the request of a dependency is an expression
    

    and finally found this https://webpack.github.io/docs/context.html. this seems a problem of webpack dynamic requires.
    after changing my to code to

     {posts.map(post => {
                let path = `${post.node.frontmatter.cover.relativePath}`;
                path = path.slice(0, path.lastIndexOf('.'))
                return <li key={post.node.fields.slug}>
                  <Link to={post.node.fields.slug}>
                    <img className="news-img" src={require('../' + path + '.png')} />
                    <h3 className="news-titles">{post.node.frontmatter.title}</h3>
                    <p className="news-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{post.node.excerpt}</p>
                  </Link>
                </li>
              }
              )}
    

    and everything is ok now.

    All 3 comments

    I google

    the request of a dependency is an expression
    

    and finally found this https://webpack.github.io/docs/context.html. this seems a problem of webpack dynamic requires.
    after changing my to code to

     {posts.map(post => {
                let path = `${post.node.frontmatter.cover.relativePath}`;
                path = path.slice(0, path.lastIndexOf('.'))
                return <li key={post.node.fields.slug}>
                  <Link to={post.node.fields.slug}>
                    <img className="news-img" src={require('../' + path + '.png')} />
                    <h3 className="news-titles">{post.node.frontmatter.title}</h3>
                    <p className="news-desc">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{post.node.excerpt}</p>
                  </Link>
                </li>
              }
              )}
    

    and everything is ok now.

    Thanks @magicly for writing up this fix, this issue really tripped me up while I was migrating from Gatsbyv 0.x to v1.x. For anyone else who stumbles across this, I wanted the same thing, but also wanted the file extension to be dynamic.

    In both my case, and in @magicly’s case from the looks of things, we are creating a cover image for an individual article, with the path coming from Markdown frontmatter. With the context of a project that’s something like the Gatsby default starter blog, you probably have some like this:

    ---
    title: The title of the post
    featured_image: ./teaser.jpg
    ---
    

    Then in your GraphQL queries on the index page that lists out all your articles, you’re going to want to include the featured_image (what @magicly was calling cover).

    frontmatter {
      title
      featured_image {
        name
        ext
        relativePath
      }
    }
    

    Now you probably want to iterate over all the posts, and show the title and the featured image on the index page. Inside your React component, you might do something like:

    // …
    
    // Create a new require context for Webpack
    const requireFeatureImage = require.context(
      `./../pages/portfolio/`, // Don’t make this a variable
      true, // Whether or not to check subdirectories
      /^.*\.(svg|png|gif|jpg|jpeg|webp|)$/ // Rough regex for extensions, maybe change this for your use case?
    )
    
    return (
      <ol>
        {pages.map(function(page, i) {
          let path = page.node.frontmatter.featured_image.relativePath
          let imgPath = `./${path.split('portfolio/')[1]}`
    
          return (
            <li key={`Item_${page.node.fields.slug}`}>
              <Link to={page.node.fields.slug}>
                <img src={requireFeatureImage(imgPath)} />
                <h2>
                  {page.node.frontmatter.title}
                </h2>
              </Link>
            </li>
          )
        })}
      </ol>
    )
    

    The docs for require.context with Webpack 2 explain the settings in more detail, but don’t really show a use case like this I don’t think. Regardless, it doesn’t appear to be so much a Gatsby issue as a fairly common pattern that requires (sorry) a bit fairly specific piece of knowledge about Webpack.

    @KyleAMathews Is this something you might be interested in me expanding on for the docs? Or is there an example / better approach for this sort of thing that I missed? Thanks!

    Part 5 of the tutorial is going to get into this but in the meantime, checkout out www and gatsbygram e.g. https://github.com/gatsbyjs/gatsby/blob/66e86d4b45dad70bfcf78861002e0108863f7985/www/src/pages/index.js#L209

    If you install https://www.gatsbyjs.org/packages/gatsby-transformer-sharp/ then linked images in frontmatter are then queryable via graphql.

    Was this page helpful?
    0 / 5 - 0 ratings

    Related issues

    kalinchernev picture kalinchernev  ·  3Comments

    timbrandin picture timbrandin  ·  3Comments

    theduke picture theduke  ·  3Comments

    benstr picture benstr  ·  3Comments

    dustinhorton picture dustinhorton  ·  3Comments