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

[Windows]: Possible entrypoint path mismatch between the manisfest.json and Illuminate/Foundation/Vite.php #19

Closed
VicGUTT opened this issue Jun 16, 2022 · 8 comments · Fixed by #20

Comments

@VicGUTT
Copy link

VicGUTT commented Jun 16, 2022

  • Laravel Vite Plugin Version: v0.2.1 (latest)
  • Laravel Version: v9.17.0 (after a composer create-project laravel/laravel:dev-vite)
  • Node Version: v16.13.1
  • NPM Version: v8.3.0

Description:

An Unable to locate file in Vite manifest: {$entrypoint} exception may be thrown on Windows caused by a mismatch between the entrypoint path strings stored in manisfest.json and an entry point given to the @vite Blade directive.

Example

Consider the following bare bones Vite config file:

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/ts/app.ts',
        ]),
    ],
});

And the @vite blade directive usage:

@vite(['resources/css/app.css', 'resources/ts/app.ts'])

This may produce the aforementioned exception.

This is because entrypoint paths in the manifest.json file may follow Windows' backslash path separator:

{
    "resources/ts/app.ts": {
        "file": "assets/app.e6f6eb1a.js",
        "src": "resources/ts/app.ts",
        "isEntry": true,
    },
    "resources\\css\\app.css": { // <-- backslashes here
        "file": "assets/app.6d9d1460.css",
        "src": "resources\\css\\app.css",
        "isEntry": true
    }
}

But as here the CSS path given to the directive ('resources/css/app.css') uses the regular slash path separator this causes $manifest[$entrypoint] to fail in line 53 of /laravel/framework/blob/vite/src/Illuminate/Foundation/Vite.php.

Note

This only seem to happen for CSS entry paths.

Possible solutions

From what I understand taking a quick look at the source code of each library, the problem could be solved in line 166 by doing something similar to:

const relativeChunkPath = path.relative(resolvedConfig.root, chunk.facadeModuleId).replaceAll('\\', '/');

And on the PHP side:

// ...

$tags = collect();

foreach ($entrypoints as $entrypoint) {
    $entrypoint = str_replace('\\', '/', $entrypoint);

    if (!isset($manifest[$entrypoint])) {
        throw new Exception("Unable to locate file in Vite manifest: {$entrypoint}.");
    }

    // ...
}

Or only on the PHP side:

// ...

if (!isset($manifests[$manifestPath])) {
    // ...

    $manifests[$manifestPath] = collect(json_decode(file_get_contents($manifestPath), true))->flatMap(
        fn(array $value, string $key): array => [str_replace('\\', '/', $key) => $value]
    );
}

// ...

foreach ($entrypoints as $entrypoint) {
    $entrypoint = str_replace('\\', '/', $entrypoint);

    // ...
}

Question:

Which approach would be better suited to be PRed ?

Steps To Reproduce:

  • Have a Windows machine
  • Check out the example scenario given above
@jessarcher
Copy link
Member

jessarcher commented Jun 17, 2022

Hey @VicGUTT,

Thanks for reporting this and for your proposed solutions!

I think the right approach would be to wrap the path in Vite's normalizePath helper:

- import { Plugin, loadEnv, UserConfig, ConfigEnv, Manifest, ResolvedConfig, SSROptions } from 'vite'
+ import { Plugin, loadEnv, UserConfig, ConfigEnv, Manifest, ResolvedConfig, SSROptions, normalizePath } from 'vite'

...

- const relativeChunkPath = path.relative(resolvedConfig.root, chunk.facadeModuleId);
+ const relativeChunkPath = normalizePath(path.relative(resolvedConfig.root, chunk.facadeModuleId));

I'll give this a try this afternoon.

@VicGUTT
Copy link
Author

VicGUTT commented Jun 17, 2022

@jessarcher, nice, thanks for the fix ! 👌

Small concern, while I'm totally fine with the status quo, the PHP side may still throw the exception if entrypoints are provided to the directive using Windows separators:

@vite(['resources\css\app.css', 'resources\ts\app.ts'])

Although I don't think anyone would do this, I believe the framework should still handle the rare cases the situation would arise as to not burden users about thinking about it.
Furthermore, Unable to locate file in Vite manifest is a misleading error message in this case as it won't be obvious to the end user that it's only due to path separators mismatch.

@timacdonald
Copy link
Member

IMO I don't think we should cater for this. Similar to how mix doesn't support this syntax. When we are in blade etc, we are in web world and should always use forward slashes.

@gofish543
Copy link

gofish543 commented Jul 21, 2022

I'm also encountering this error with app.css....
Below is a dump from the Vite.php manifest

  "resources/js\app.css" => array:2 [▶
    "file" => "assets/app.b511f860.css"
    "src" => "resources/js\app.css"
  ]
  "node_modules/@fortawesome/fontawesome-pro/css\all.css" => array:2 [▶
    "file" => "assets/all.36d51b2e.css"
    "src" => "node_modules/@fortawesome/fontawesome-pro/css\all.css"
  ]

And my Vite config...

import { defineConfig, loadEnv } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import { viteStaticCopy as copy } from 'vite-plugin-static-copy';

export default defineConfig(({ mode }) => {
    const env = loadEnv(mode, process.cwd(), '');

    return {
        plugins: [
            laravel({
                input: [
                    'resources/css/app.css',
                    'resources/js/app.js',
                ],
                refresh: true,
            }),
            vue(),
            copy({
                targets: [
                    {
                        src: 'resources/images',
                        dest: '../'
                    }
                ]
            }),
        ],
        build: {
            sourcemap: mode !== 'production'
        },
        esbuild: {
            drop: mode === 'production' ? ['console', 'debugger'] : [],
        },
        resolve: {
            alias: {
                'vue': 'vue/dist/vue.esm-bundler.js'
            }
        }
    };
});

@timacdonald
Copy link
Member

This problem has been addressed in later releases, and what is more with Vite 3, we are no longer responsible for generating the CSS paths.

I recommend updating to the latest package and Vite release. You may need to adjust your version constraints to get to the latest versions.

@timacdonald
Copy link
Member

Looks like there is an issue in Vite itself. To keep up with this issue, watch this issue: #101 (comment)

@VicGUTT
Copy link
Author

VicGUTT commented Aug 10, 2022

Just dropping by to say Thank you ! @jessarcher for the implementation here and @timacdonald for the upstream PR. Freaking love Open Source ! 💪🏾 ❤️

@timacdonald
Copy link
Member

💖💖💖

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

Successfully merging a pull request may close this issue.

4 participants