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

Generated static files html files have wrong assets paths #8158

Closed
emuraton opened this issue Jul 29, 2019 · 34 comments
Closed

Generated static files html files have wrong assets paths #8158

emuraton opened this issue Jul 29, 2019 · 34 comments

Comments

@emuraton
Copy link

Bug report

Describe the bug

I'm tried to generate a static site with Next js v9.0.2 and got assets linking by default to /_next/static/something/something.js. But by default build and export create a folder .next.

I think its related to: https://github.com/zeit/next.js/blob/4bcf6aabe7af477a8e58893f03622d84047abf2b/packages/next/pages/_document.tsx#L410

To Reproduce

  1. Create a static page
  2. Build it
  3. Open the html page generated
  4. See the source of every script inside the html page

Expected behavior

Generated path should begin with ./next/

Screenshots

Screen Shot 2019-07-29 at 12 25 54

System information

  • OS: macOS
  • Version of Next.js: 9.0.2
@Timer
Copy link
Member

Timer commented Jul 29, 2019

Hey @emuraton!

The /_next/ path is actually a value handled by the Next.js server. This path is mounted to .next/, or whatever distDir is customized to.

Sorry for the confusion!

@Timer Timer closed this as completed Jul 29, 2019
@emuraton
Copy link
Author

Hey @Timer,

Thanks for the clarification, but right now after build time, I try to handle the static files with serve and so I guess because its not handled by Next.js server it fails.

I will set distDir to fix my issue. But would it not be more practical that both values match by default?

@Timer
Copy link
Member

Timer commented Jul 29, 2019

@emuraton You should not set distDir -- sorry if my suggestion came off this way.

It sounds like you're trying to do something non-standard, you do not need to handle serving any of these files yourself.

Can you please explain what you're trying to accomplish more?

@emuraton
Copy link
Author

I want Next.js to output static files for me, and then I want to serve my static files with https://www.npmjs.com/package/serve.
And when I do, I get /404 on my assets because of /_next/ path.

@Timer
Copy link
Member

Timer commented Jul 29, 2019

It sounds like you're looking for the next export command!

https://github.com/zeit/next.js#static-html-export

@emuraton
Copy link
Author

emuraton commented Jul 29, 2019

Sorry forgot to mention Im using the export cmd from Next.js.
(from the /out directory)
Screen Shot 2019-07-29 at 16 18 35

@Timer
Copy link
Member

Timer commented Jul 29, 2019

@emuraton sorry, but we cannot provide further support without a reproducible demo provided.

@emuraton
Copy link
Author

Ok thanks for your time 👍

@Piets0n
Copy link

Piets0n commented Feb 10, 2020

Hi,

i came across the same Problem as @emuraton mentioned.

After i do the basic export command and open the generated index.html i get this error
Bildschirmfoto 2020-02-10 um 10 24 22
(this error comes straight from the basic export example)

If i add a ./ in front of all /_next/static... , the file is working as intended.

@keroloswilliam
Copy link

we are hitting the same issue here

to fix this issue from our side we had to set distDir to _next we were following the instructions inside the docs

just clarification that I am not saying this is the standard i am just this was a fix to issue appeared

@keidarcy
Copy link

keidarcy commented May 23, 2020

next export will generate all js src path like /_next/.., I manually changed it to ./_next/.., it's kind of confusing.

@cargallo
Copy link
Contributor

cargallo commented Jul 7, 2020

Hi, why is this issue closed? It's still happening!!!

@timneutkens
Copy link
Member

@cargallo not sure what you're referring to, this issue has a reply: #8158 (comment)

It's impossible to help you based on "Why is this closed" without a full reproduction or even any information about your issue.

@cargallo
Copy link
Contributor

cargallo commented Jul 8, 2020

Hi @timneutkens I followed the start learning of the oficial nextjs web. If you run "next build && next export" the resulting html site (that command is for generating just a static site wich not requires nodejs server or whatever server) the links of the css and js resources attached by nextjs, their path is in this way

<link rel="stylesheet" href="/_next/static/css/97614410f90d914be5ee.css"/>

The problem is not in wich name the folder has but in the way that it is referenced since in plain HTML it has to have a dot before the first slash, like this

<link rel="stylesheet" href="./_next/static/css/97614410f90d914be5ee.css"/>

I think that if nextjs can refer the files in this way it could be run in both, plain HTML and nodejs server or vercel environment.

Reggards,

@cargallo
Copy link
Contributor

cargallo commented Jul 12, 2020

Hi @timneutkens , could you check the detailed infromation? Thanks in advance!

@timneutkens
Copy link
Member

The out directory has to be hosted through a web server, we currently do not support using the html standalone

@cargallo
Copy link
Contributor

I don't understand therefore what is next export command for? And it's just easy to implement it has no sense at all.

@cargallo
Copy link
Contributor

For otherones wich have this same issue just do this manual step after doing
next build && next export
edit the result html file and replace all "/_next/static" with "./_next/static" until they have the time and desire of fixing the issue

image

@cargallo
Copy link
Contributor

cargallo commented Jul 16, 2020

DO NOT USE THIS SOLUTION ANY MORE !!!
USE THE SOLUTION BELOW INSTEAD #8158 (comment)

To automate the steps commented above:

yarn add --dev replace-in-files-cli

Then, add this two scripts in your package.json

"build-static": "next build && next export && npm run build-static-repair-index",

"build-static-repair-index": "replace-in-files --string \"/_next/static\" --replacement \"./_next/static\" out/index.html"

Then just call

npm run build-static

Explanation: The build-static-repair-index script will replace /_next/static with ./_next/static in the index.html file inside out folder wich is generated when you export your entire site to plain html wich can run standalone without any server.

Hope this helps. Reggards,

@asos-albinotonnina
Copy link

asos-albinotonnina commented Jul 24, 2020

@cargallo it does yes, thank you. And it works just fine.

Shame, this should be a very prominent configuration setting IMO.
It doesn't look so uncommon to have the need to host say a static app in a subfolder.
I appreciate there is a base option to be used but that doesn't solve the issue entirely, or at least it creates others.

Gracias :)

@stevenmunro
Copy link

I experienced a similar issue all of a sudden which I thought was extremely weird. After next export and uploading the out folder to the server, no matter how many times I ran yarn build there were always 404 errors.

Then I emptied my bin (or trashcan on Windows)... and then it started working again as expected.

@attack-monkey
Copy link

I don't understand how more people are not complaining about this.
@cargallo - thank you for the work around 👍

@spudmashmedia
Copy link

spudmashmedia commented Sep 6, 2020

Thanks @cargallo 👍
Was trying to serve static exported files through an Electron app and was wondering why all the styles were missing.
Post build-export find/replace will do for now.

[EDIT]
After poking around a bit, there's an attribute in the next.config.js called assetPrefix that lets you prefix a path to the static resources in the index.html (see https://nextjs.org/docs/api-reference/next.config.js/cdn-support-with-asset-prefix + #9916)

I've set my config to the following and it did the trick:

next.config.js

module.exports = {
  assetPrefix: ".",
};

Generated output: index.html

    <script
      src="./_next/static/SAfl4nj0fgiMC88TrHu7s/_ssgManifest.js"
      async=""
    ></script>

@cargallo if you haven't done so already, you might want to use this instead of npm: replace-in-files-cli method 👍

@crzurita
Copy link

I hosted the content of "out" folder on a free server like 000webhost (doesn't have node) and works pretty well.

But... the first time I had this trouble with a laragon server. After that I maked a tool for fix this.

Right now, after to host on a php server, I know that the tool is useless, but if it is util for you, use it tool

@Aagbator
Copy link

Aagbator commented Nov 3, 2020

With Sass I configured my next.config.js as follows

const withPlugins = require("next-compose-plugins");
const withImages = require('next-images');
const withSass = require('@zeit/next-sass')

module.exports = withPlugins([[withSass({
assetPrefix: ".",
}), withImages()]]);

@OHHAKO
Copy link

OHHAKO commented Nov 27, 2020

It's still happening!
@spudmashmedia your advice really helpful to me. but it works only to specific element. (Doesn't work to img tag path)
thanks!

@krish4u
Copy link

krish4u commented Dec 16, 2020

In my case I am having multiple sub folders based on navigation structure where prefixing "." in front of "/_next/" is not helping out.
We are trying to generate the critical CSS automatically based on "out" folder. Hence the CSS file path is not proper in the exported pages we are not able to generate the critical CSS automatically.

Currently as a workaround I am using "serve" and using the "localhost" url to generate the critical CSS manually.

@spudmashmedia
Copy link

@OHHAKO Sorry for the late reply.

Are you putting your image resources under ./public folder?
(see https://nextjs.org/docs/basic-features/static-file-serving)

Example

When you layout the public folder like the following:

+ root
|
+ - public
       +
       |
      +- img
             +- red.jpg
             +- green.jpg
             +- blue.jpg
             +- none.jpg

Performing a "next build" + "next export", the images will produce an out folder with:

+ root
|
+ - out
       +
       |
      +- img
             +- red.jpg
             +- green.jpg
             +- blue.jpg
             +- none.jpg

Then you can reference the images in your project like:

pages/index.js

const Home = () => {
   return (
      <div>
         <img src="/img/red.jpg" width={100} height={100} />
         <img src="/img/green.jpg" width={100} height={100} />
         <img src="/img/blue.jpg" width={100} height={100} />
      </div>
  );
}

export default Home;

OR via a component
./component/MyImage.js

const MyImage = (props) => {
  let { src, width, height } = { ...props };

  let uri = `/img/${src ?? "none"}.jpg`; // obviously add more error handling here to prevent folder traversal, but you get the gist!
  let w = width ?? 100;
  let h = height ?? 100;

  return <img src={uri} width={w} height={h} />;
}

export default MyImage;

./pages/index.js

import MyImage from "../components/MyImage"

const Home = () => {
   return (
      <div>
         <MyImage src="red" width={100} height={100} />
         <MyImage src="green" width={100} height={100} />
         <MyImage src="blue" width={100} height={100} />
      </div>
  );
}

export default Home;

NOTE

You will get an error if you attempt to use the inbuilt "next\Image" during an export

pages/index.js

import Image from "next/image"

const Home = () => {
   return (
      <div>
         <Image src="/img/red.jpg" width={100} height={100} />
         <Image src="/img/green.jpg" width={100} height={100} />
         <Image src="/img/blue.jpg" width={100} height={100} />
      </div>
  );
}

export default Home;

Error:

Error: Image Optimization using Next.js' default loader is not compatible with `next export`.
Possible solutions:
  - Use `next start`, which starts the Image Optimization API.
  - Use Vercel to deploy, which supports Image Optimization.
  - Configure a third-party loader in `next.config.js`.
Read more: https://err.sh/next.js/export-image-api

@Irrelon
Copy link

Irrelon commented Feb 15, 2021

Hey folks. The issue being experienced by most of the comments above appears to be because once a next export is done and you have the out folder, if you serve the out folder under another folder, the urls to the assets will no longer resolve.

Imagine a basic project folder set up, something like:

My Project
--> pages
------> index.js
--> public
--> out

Then start an http server with the My Project folder as the root. The out folder from the browser url is then something like: http://localhost:8000/out/

The asset path Next.js uses ASSUMES that the out folder will be the root of your web server host.

Modifying the assetPrefix to "." works for the above layout, but when you try to nest your pages any further it fails again.

e.g.

My Project
--> pages
------> index.js
------> login
----------> index.js
--> public
--> out

Now when you access http://localhost:8000/out/login/ the page is 404.

Modifying the trailingSlash option solves this so:

With a next.config.js of

module.exports = {
  assetPrefix: './',
  trailingSlash: true,
  reactStrictMode: true
}

But then, when you access http://localhost:8000/out/login/, the assets all try to load from http://localhost:8000/out/login/_next/***

The _next folder is assumed to be ./_next, relative to the current page URL path (/out/login), rather than the root of the out folder (/out).

Furthermore, client-side routing will work and render the pages but refreshing will 404 because the navigated URL changes from http://localhost:8000/out/login/ to http://localhost:8000/login/ when you click on a link client-side. /login doesn't exist at the project folder root, only inside /out, as /out/login.

All of this is down to the relative vs absolute paths being used or not.

The question becomes, how do you configure Next.js to output HTML with paths that will operate without knowing ahead of time what folder or sub-folder they will be served from? I think many people commenting assume that the paths would take into account their position within the file tree when they are exported.

At the compile time it seems totally possible to know the relative path to the root of the _next folder from any page or component that might be using it but the URLs do not resolve that way at present unless I'm missing some config flag? I read the docs extensively to try and solve this one!

Essentially, at present as far as I can tell, you need to modify the config according to the place the code is going to be deployed (see basePath documentation). This seems pretty counterintuitive, although I realise that it is a non-issue for Vercel since they are deploying to known root paths in all cases.

@chrisandrew
Copy link

Thanks to all of you who took time to share your solutions to this issue. I like next.js, but I have been very frustrated as I ran into the same issues listed above. If nothing else, the next documentation should be more clear about the limitations of SSG. It isn't what I consider "true" SSG given the implicit dependency that remains on the next server.

@amir-mln
Copy link

amir-mln commented Apr 6, 2021

well, like every one else I had faced this issue of wrong assets paths and it did not get solved by adding . to start of the string.
I realized that I need to remove the / from the start of the path entirely.
Thanks to @cargallo solution, I came up with my own script.
So first you need to install the library:
npm i --save replace-in-file
Edit: The document of the library uses --save flag for installation but we don't need to install this as a dependency in our next.js project. Use -D or --save-dev instead.

Then create a replacer.js at the root of your project and paste the below code in it:

const replace = require("replace-in-file");
const options = {
  //you may need to modify the file address to suite your project
  files: "./out/index.html",
  from: [/src="\//g, /href="\//g],
  to: ['src="', 'href="'],
};
(async function () {
  try {
    const results = await replace(options);
    console.log("Replacement results:", results);
  } catch (error) {
    console.error("Error occurred:", error);
  }
})();

Add the followings to your package.json "scripts":

"export": "next build && next export && npm run replaceFilePaths ",
"replaceFilePaths": "node replacer.js",

now, after runing the scripts you must be able to serve the out folder even from a different root.

Edit-2: as @peterDuot-stationfive mentioned it should be node replacer.js instead of node replaceInFiles.js.

@alex-drocks
Copy link

alex-drocks commented May 22, 2021

create a file named next.config.js
image

Use the basePath property to define your server path but only in production builds:
image
docs link: https://nextjs.org/docs/api-reference/next.config.js/basepath

If your favicon does not serve because you are using a subfolder on your domain, use a conditionnal check like this when you define favicon link:
image

@peterDuot-stationfive
Copy link

should be node replacer.js
but I used this and it's working in my local. Thank you :)

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests