catamphetamine / webpack-isomorphic-tools

Server-side rendering for your Webpack-built applications (e.g. React)
MIT License
1.25k stars 48 forks source link

'Cannot find module' when using webpack loaders #96

Closed edorivai closed 8 years ago

edorivai commented 8 years ago

Hi,

Apologies if I missed something stupid, but I've been working off of the react-redux-universal-hot-example, which uses these tools, and have been running into trouble. Note: I'm only having issues with the .server() functionality. The webpack-isomorphic-tools/plugin works fine.

Basically I want to use the responsive-loader like so:

import logo from 'responsive?sizes[]=100,sizes[]=200,sizes[]=300!./logo.png';
...
<img alt='logo' { ...pick(logo, 'src', 'srcSet') } />

Now the image assets are defined like so:

assets: {
    images       : {
        extensions: ['jpeg','jpg','png','gif'],
        parser    : WebpackIsomorphicToolsPlugin.url_loader_parser
    }
}

Which is also shown by the logs:

...
[1] [webpack-isomorphic-tools] [debug]  registering a require() hook for *.png
[1] [require-hacker] [debug] Hooking into *.png files loading
...

However, it seems like either this module, or require-hacker is having trouble loading my image through the loader:

Error: Cannot find module 'responsive?sizes[]=100,sizes[]=200,sizes[]=300!./logo.png'

It seems to me that the require-hacker is not matching the png extension to my import. I'm aware of your updated universal-webpack project, but it would be awesome if I wouldn't have to refactor our entire setup :)

Thanks!

catamphetamine commented 8 years ago

First, post your webpack-assets.json

edorivai commented 8 years ago

After doing a regular webpack build (without the isomorphic tools server):

{
    "javascript": {
        "main": "/dist/main-4741642bcf773c303347.js"
    },
    "styles": {
        "main": "/dist/main-4741642bcf773c303347.css"
    },
    "assets": {
        "./~/responsive-loader?sizes[]=200w,sizes[]=900w!./src/components/Footer/logo.png": {
            "srcSet": "/dist/b543654d2aa566278f4a55fa57f60710-200.png 200w,/dist/173c90859b68dae28f380594dab6600c-900.png 900w",
            "images": [
                {
                    "path": "/dist/b543654d2aa566278f4a55fa57f60710-200.png",
                    "width": 200
                },
                {
                    "path": "/dist/173c90859b68dae28f380594dab6600c-900.png",
                    "width": 900
                }
            ],
            "src": "/dist/b543654d2aa566278f4a55fa57f60710-200.png"
        },
        "./src/components/FlightSearchForm/paper-plane.png": "/dist/e43977ae42c5fd34ddc5f704b5379647.png",
        "./src/components/Footer/logo.png": "/dist/40ad81f97f992aa2762104859a58f3b0.png",
        "./src/components/search/CalendarInput/pick-dates-arrows.png": "data:image/png;base64,(...)",
        "./src/components/search/DestinationInput/airplane-land.png": "data:image/png;base64,(...)",
        "./src/components/search/OriginInput/airplane-takeoff.png": "data:image/png;base64,(...)",
        "./src/components/AirSearch/AirSearch.scss": {
            "airSearch": "_2EWuPkdN7-e_9a4Lyck7bD",
            "input": "_26laaCQwJnVw2Dp2w-6PhK",
            "container": "_2izjQPwb252hdg1VOZ3KH9",
            "suggestion": "GLkZ2a4Q8GUlEBT9roaqk",
            "focused": "_2BeuLz_R9ZntuWUlrg1_WS"
        },
        "./src/components/Footer/Footer.scss": {
            "footer": "_2nhzBA1RlNKOVN_nNggXzW",
            "columnContainer": "_3dgNKmQSUHP_s-80dcoG1J",
            "column": "_2s5Kwhrv5lnUGjWHVoaWv5",
            "disclaimer": "_1uXyy1r8U9wrrnNh8NRCGo"
        },
        "./src/components/common/NewsletterSection.scss": {
            "newsletterSection": "_3lNtYGZLk_EXefXckLuHUU"
        },
        "./src/containers/App/App.scss": "// removed by extract-text-webpack-plugin",
        "./src/containers/Deals/Deals.scss": {
            "deals": "_2ZBPCFQ3eIrR7OdYz_fy8t"
        },
        "./src/containers/Home/Home.scss": "// removed by extract-text-webpack-plugin"
    }
}

I trucated the data urls for brevity.

catamphetamine commented 8 years ago

So, yeah, it says Cannot find module 'responsive?sizes[]=100,sizes[]=200,sizes[]=300!./logo.png' because this module isn't present in your webpack-assets.json. Instead you have ./~/responsive-loader?sizes[]=200w,sizes[]=900w!./src/components/Footer/logo.png.

What you could do is to modify path parser for responsive-loader assets. Try adding a dedicated assets entry for that type of require() calls. The extensions will stay the same, but path function will be different. Make it match only ./~/responsive-loader?... paths and transform them to responsive?.... I don't know why the sizes are different in both cases.

edorivai commented 8 years ago

Ah, thanks for the explanation. I think I've made some progress, but not quite there yet.

So I'm importing the following:

import logo from 'responsive?sizes[]=200w,sizes[]=900w!./logo.png';

And I've modified my asset entry like so:

        images       : {
            extensions: [
                'jpeg',
                'jpg',
                'png',
                'gif'
            ],
            path: function(module) {
                if (/\.\/~\/responsive-loader/.test(module.name)) {
                    return module.name.replace('./~/responsive-loader', 'responsive');
                }
                return module.name;
            },
            parser    : WebpackIsomorphicToolsPlugin.url_loader_parser
        }

Which results in the following key in the assets json:

"responsive?sizes[]=200w,sizes[]=900w!./src/components/Footer/logo.png"

It obviously still complains:

Error: Cannot find module 'responsive?sizes[]=200w,sizes[]=900w!./logo.png'

because the imported url is relative to the component (./logo.png), while the asset refers to the path relative to the root (./src/components/Footer/logo.png).

I'm seeing other assets that are also identified relative to the root: "./src/components/FlightSearchForm/paper-plane.png", and those don't seem to pose an issue. I'm guessing the loading syntax (responsive?...) is messing up with the matching logic.

Should I import the image using some different syntax?

Thanks so far!

Btw, sizes were different because I'm reproducing on a different machine, and didn't push on the other.

catamphetamine commented 8 years ago

You can try running the whole thing in debug mode which will generate webpack-stats.json. Then upload that webpack-stats.json and post the link to it here. Maybe github will upload it automatically when you paste the contents of the file in the comment box.

catamphetamine commented 8 years ago

Oh, no, I get it, the issue is in the other place.

catamphetamine commented 8 years ago

Well, I guess, there's currently no way to make it work, because require('responsive?...') will look for responsive?... file existence (on disk) and since there's no such file then it will throw Error: Cannot find module 'responsive?...'. I guess you may try moving to universal-webpack instead, because I don't see how this kind of require() calls could work with the current implementation of this library.

edorivai commented 8 years ago

Okay, understood. Thanks for the swift replies!

catamphetamine commented 8 years ago

File existence requirement is not mine and is Node.js'es. https://github.com/halt-hammerzeit/webpack-isomorphic-tools#cannot-find-module

edorivai commented 8 years ago

Out of curiousity. Does that mean that it is entirely impossible to use webpack loaders this way in a universal app? I mean to define the loader in the import string.

catamphetamine commented 8 years ago

It is possible to bypass Node.js file existence requirement by using .global_hook instead of .hook https://github.com/halt-hammerzeit/require-hacker#global_hookmeaningful_id-resolve-options It can be implemented in this library (either instead of the regular file extension hook or additionally for loaders only). I'll see.

catamphetamine commented 8 years ago

Okay, seems that I made it. Install the latest version of the package, revert to the initial assets configuration (no custom path parsing) and post back on results.

edorivai commented 8 years ago

Awesome! Works for my use-case. Thanks a lot.