NextJS部署到特定的URL路径

时间:2020-02-28 12:49:32

标签: reactjs next.js

我正在开发我的第一个NextJS应用程序。当我运行“ npm run dev”或“ npm run start”时,它将我的应用程序部署到

http://host:port/

当我导航到页面时,URL变为

http://host:port/page1

我需要有自己的特定URL,例如

http://host:port/my-test-application/path-for-my-app/
http://host:port/my-test-application/path-for-my-app/page1

此外,我的应用程序具有许多链接到应用程序其他区域的元素,我需要这些元素也可以通过basePath转到URL,而不仅仅是转到根路径。

我还将把该应用程序分配给具有不同basePath的其他服务器,因此无法在我的应用程序中对其进行硬编码。

我该怎么做?

对于其他应用程序,例如react / vue / angular / native JS,我只需构建我的应用程序并将构建代码放在服务器上的“ my-test-application / path-for-my-app”文件夹中。 / p>

我在NextJS应用程序中尝试了此操作,但遇到一个错误,即找不到“ .next”文件夹。

我用Google搜索,可以找到一些有关使用“ assetPrefix”或“ Zones”的参考。但是我真的不明白我该怎么办。

如何将我的应用程序部署到特定的URL

解决方案1:重组“页面”-无法使我部署到具有不同basePath的其他服务器

我可以在“页面”目录中创建文件夹结构,并更改所有元素以使用此文件夹结构。

|- pages
     |- my-test-application
           |- path-for-my-app
                |- index.js
                |- page1.js


<Link href="/my-test-application/path-for-my-app/page1" >

我不喜欢这种解决方案,因为basePath已硬编码到我的应用程序中,以适应部署设置。

如果我想将我的应用程序部署在具有不同basePath(即以下)的2台服务器上,则必须具有2个版本的代码。

http://host:port/my-test-application_1/path-for-my-app/page1
http://host:port/my-test-application_2/diff-path-for-my-app/page1

已更新:我已于3月5日更新了此问题,以包括我需要s正常工作以及不喜欢的解决方案。

5 个答案:

答案 0 :(得分:10)

在Next.js≥9.5中,可以在next.config.js中设置basePath。例如,如果您希望整个Next.js应用程序位于/docs上,则可以使用:

// next.config.js
module.exports = {
  basePath: '/docs'
}

下一步将确保从正确的位置提供所有资产,并且它将为应用程序中的所有Link以及在使用next/router进行程序设计导航时自动为该基本路径添加前缀。例如,

<Link href="/about">
  <a>About Page</a>
</Link>

将被转换为链接到/docs/about

router.push('/about')

这意味着您可以更改basePath,而无需在应用程序的实际代码中进行任何更改。

答案 1 :(得分:3)

要补充这里的答案,仅使用 basePath 是不够的。 basePath 非常适合自动指向链接,但它对从公共目录提供的静态文件没有任何作用。

例如,您在 public/img/my-img.pngimg 元素中将 Image 称为 <img src="img/my-img.png" /><Image src="/img/my-img.png" />,您必须将其更改为 {{ 1}} 或 <img src="your-sub-path/img/my-img.png" /> 分别。

答案 2 :(得分:2)

我找到了使用NGINX反向代理具有基本路径的URL的解决方案。

有用的链接

应用程序更改

依赖项

  • next-images:为了在使用反向代理时从“ public”导入静态图像
  • @ zeit / next-css:为了使用样式表文件
  • 以及通常的NextJS依赖项

next.config.js

在应用程序的根目录中添加一个“ next.config.js”文件,以便您可以指定“ assetPrefix”和“ publicRuntimeConfig.basePath”

  • assetPrefix:在访问组件,样式表,页面等时,由NextJS使用
  • publicRuntimeConfig.basePath:在s中使用,因此指定要添加到链接的前缀,在使用公共图像时在“”元素的“ src”标签中使用

示例

const isProd = process.env.NODE_ENV === 'production'

// Enable importing of css stylesheets
const withCSS = require("@zeit/next-css");
const withImages = require('next-images');

/*
 * Gets the BASE_PATH from the command used to start this app.
 * If BASE_PATH is specified but it does not start with a "/" 
 * then add it. 
 */
function getBasePath() {
    var basePath = ''

    if (isProd && process.env.BASE_PATH){
        if (process.env.BASE_PATH.startsWith("/") ){
            basePath = process.env.BASE_PATH;
        } else {
            basePath = "/" + process.env.BASE_PATH;
        }
    } 

    console.log("getBasePath() : isProd = " + isProd);
    console.log("getBasePath() : basePath = " + basePath);

    return basePath
}

module.exports = withCSS(withImages({
    assetPrefix: getBasePath() ,

    publicRuntimeConfig: {
        basePath: getBasePath() ,
    },

}));

静态图片

使用“下一个图像”来导入图像并在src标记中引用导入的对象

更改对静态映像(在/ public文件夹中的静态映像)的任何引用以具有基本路径前缀。例如,我的“页脚”组件具有以下

import '../stylesheets/main.css';

import img1 from '../public/image_name1.png'
import img2 from '../public/image_name2.png'

export default class o extends React.Component {

    render(){
        var prefix = publicRuntimeConfig.basePath
        return  (
            <div >
                <a className="icon" href="http://www.image_name.com" >
                    <img src={img1} alt="image_name1"/>
                </a>
                <a className="icon" href="http://www.image_name2.com">
                    <img  src={img1} alt="image_name2"/>
                </a>
            </div>
        );
    }
}

注意:我试图使用publicRuntimeConfig.basePath作为src URL的前缀(如下所示),但这在我的部署环境中不起作用(请参见以下内容)

    import getConfig from 'next/config'
    const { publicRuntimeConfig } = getConfig()
    ...
    ...
    <a className="icon" href="http://www.image_name.com" >
        <img src={`${publicRuntimeConfig.basePath}/image_name1.png`} alt="image_name1"/>
    </a>

链接

更改您的链接以使用基本路径前缀,例如在我的“标题”组件中,我具有以下内容

import Link from 'next/link';
import '../stylesheets/main.css';

import getConfig from 'next/config'
const { publicRuntimeConfig } = getConfig()

const detailId1 = "banana"

const Header = () => (
    <div>
        <div>
            <Link href={`${publicRuntimeConfig.basePath || ''}/`}>
                <a className="linkStyle">Home</a>
            </Link>

            <Link href={`${publicRuntimeConfig.basePath || ''}/about`} >
                <a className="linkStyle">About</a>
            </Link>

            <Link href={`${publicRuntimeConfig.basePath || ''}/details/[id]`} 
                  as= {`${publicRuntimeConfig.basePath || ''}/details/${detailId1}`} >
                <a className="linkStyle">Details Var 1</a>
            </Link>
        </div>
  </div>
);

export default Header;

注意:在博客https://levelup.gitconnected.com/deploy-your-nextjs-application-on-a-different-base-path-i-e-not-root-1c4d210cce8a中,它包含一个“ Link.tsx”,为您添加了前缀,因此您只需使用该Link组件(从“ ./Link导入Link”即可。 .tsx“;),而不是nextJS版本(从“ next / link”;导入Link)。但是,当我在链接URL中有变量时,“ Link.tsx”不适用于我。

运行您的nextjs应用

在不希望使用基本路径的情况下在本地运行应用程序时,只需运行即可

npm run dev

由于未指定BASE_PATH,因此应可从“ http://localhost:3000”访问应用程序,并且src值应为“ /image_name1.png”,将鼠标悬停在s上时,将看到链接为“ {{3 }}“

要使用基本路径运行时,请执行以下操作

export BASE_PATH=a/b
npm run dev

注意:由于我的环境中的某些原因,如果我指定“ export BASE_PATH = / a / b”(/在路径的开头),则会在该路径的开头添加一个文件夹目录。因此,我在没有开始/的情况下指定了它,并且next.config.js中的代码在需要时添加了开始/。

您已经设置了基本路径/assetPrefix/publicRuntimeConfig.basePath,因此无法在“ http://localhost:3000/pagename”访问您的应用程序。现在您需要反向代理。

NGINX:反向代理

我发现最简单的设置是使用NGINX docker映像。您需要使用包含重定向到NextJS应用程序的配置来运行NGINX。

创建一个文件夹,然后在该文件夹中添加一个“ default.conf”文件。确保在启动nextjs应用程序时,放置在“位置”中的路径与您为BASE_PATH指定的相同路径。

server {
    listen 80;
    server_name  localhost;

    location /a/b/ {
        proxy_pass http://myhost:3000/;
    }       
}

重要说明:

  • 您必须在proxy_pass URL的末尾加上/,否则其他路径不会传递到NextJS应用程序中
  • 如果在该位置使用变量,则必须确保包括传递路径

示例

location ~ /a/b/(.*)$ {  
    set $upstream http://myhost:3000/$1;
    proxy_pass $upstream;
}

在该目录的命令提示符下,运行NGINX docker映像,告诉它使用您的配置文件。

docker run --name mynginx1 -v C:/zNGINX/testnginx/conf:/etc/nginx/conf.d -p 80:80 -d nginx
  • 泊坞窗容器的名称为“ mynginx1”
  • v参数告诉它将计算机上“ C:/ zNGINX / testnginx / conf”中的所有文件复制到docker容器中的“ /etc/nginx/conf.d”目录中。这会将您的“ default.conf”复制到Docker容器中,NGINX将读取该配置文件。
  • 注意:请确保您在docker位置(“:/etc/nginx/conf.d”)的路径中具有“ conf.d”,我阅读的博客不包括此部分,它仅指定了“:”: / etc / nginx /”,如果没有该图片,则无法启动。
  • p参数告诉在端口80上运行NGINX

转到以下网址

http://localhost:80/a/b/

NGINX会将URL重定向到“ http://localhost:3000”。因此,现在应该可以从具有基本路径的URL访问您的应用程序。单击s应该可以,链接应该包含转到NGINX的基本路径,该路径将重定向回应用程序,并剥离基本路径,并保留所有其他路径。

使用Docker的Real World Server部署

如果将应用程序部署到服务器(如本地运行一样),则可以构建应用程序,然后将相关文件/文件夹复制到服务器计算机上。在构建和运行应用程序时,请确保已设置BASE_PATH

export BASE_PATH=a/b
npm run build

cp package*.json [server_location]
cp next.config.js [server_location]
cp ./next [server_location]

然后在该服务器上运行

npm install
export BASE_PATH=a/b
npm run start   

注意:如果您在应用中引用了“公共”中的图像,请使用“下一个图像”并导入图像,而不要使用publicRuntimeConfig.basePath作为前缀。当我做后者时,没有找到图像。有关示例,请参见关于图像的部分。

答案 3 :(得分:1)

您可以使用自定义服务器在您的特定URL上创建NextJS应用程序工作:

在此处查看示例:

https://github.com/zeit/next.js/tree/canary/examples/custom-server-express

关键点是将您的特定网址添加为API,然后将用户的请求转发到您要投放的特定页面:

const express = require('express')
const next = require('next')

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  const server = express()

  server.get('/my-test-application/path-for-my-app', (req, res) => {
    return app.render(req, res, '/index', req.query)
  })

  server.get('/my-test-application/path-for-my-app/page1', (req, res) => {
    return app.render(req, res, '/page1', req.query)
  })

  server.get('/posts/:id', (req, res) => {
    return app.render(req, res, '/posts', { id: req.params.id })
  })

  server.all('*', (req, res) => {
    return handle(req, res)
  })

  server.listen(port, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}`)
  })
})

答案 4 :(得分:0)

我通过在next.config.js中编写重定向来解决此问题:

const withImages = require('next-images')

module.exports = withImages(withSass({
    cssLoaderOptions: {
      url: false
    },
    //Might need to change it here, before going to the production
    assetPrefix: 'http://localhost:3000',
    postcssLoaderOptions: {
      config: {
        ctx: {
          theme: JSON.stringify(process.env.REACT_APP_THEME)
        }
      }
    }
}));