Используйте next.js для перехода от разработки к развертыванию

внешний интерфейс сервер JavaScript React.js

next.jsотличный легкий весreactИзоморфная структура, которую можно использовать для быстрой разработки рендеринга на стороне сервера на основеreactзаявление. существуетnext.jsОфициальный сайт рекомендует использоватьnowДля развертывания приложений, но для домашних пользователей или пользователей с особыми потребностями, развертывание на настраиваемых серверах может быть тем, чего хочет большинство людей. В связи с недавней ревизией официального сайта компании я хотел бы поделиться своим опытом от разработки до развертывания.

Я до сих пор смутно помню, как впервые использовал егоnext.jsбыл в прошлом году (2017), в то время с использованиемnext.js2.x версия,reactЕще версия 15, год спустя, сейчасreactбыл разработан до версии 16, в то время какnext.jsОн разработан до версии 6.0, скорость итерации поражает, и в процессе использования новой версии есть много ям.

используемая технология

Поговорим о том, какие технологии используются на этот раз Ниже перечислены основные технологии или библиотеки инструментов, используемые в проекте.

Веб-фреймворк следующего поколения, разработанный оригинальной командой Express, используется для предоставления веб-сервисов.

Это высокопроизводительный HTTP и обратный прокси-сервер, а также сервер IMAP/POP3/SMTP (из энциклопедии Baidu), разработанный россиянами. Используется для предоставления статических файловых служб, сертификатов https и прокси-служб.

библиотека пользовательского интерфейса javascript

легкийreactИзоморфная структура приложения

Разработано Ant Financialreact的Набор библиотек компонентов среднего и внутреннего продукта.

на основеreactанимационные решения

Определить, находится ли компонент в текущей области просмотраreactкомпоненты

Менеджер процессов для приложений Node с балансировкой нагрузки

Изоморфный API-интерфейс WHATWG Fetch

стадия развития

Сказав так много, давайте перейдем к этапу разработки, и первым шагом будет построение структуры проекта.Здесь мы делимся нашей структурой проекта:

📁.vscode

vscodeконфигурационный файл

📁component

reactкомпоненты

📁common

В общедоступную часть я помещаю информацию панели навигации, глобальные переменные и глобальные стили и т. д.

📁pages

Все страницы проекта, а такжеnext.js входной файл для каждой страницы

📁static

статические файлы

📁styles

таблица стилей для каждой страницы

🗄index.js

файл запуска узла

🗄.babelrc

babelконфигурационный файл

🗄.gitignore

конфигурационный файл git

🗄ecosystem.config.js

pm2конфигурационный файл

🗄next.config.js

next.js конфигурационный файл

🗄postcss.config.js

postcss конфигурационный файл

🗄nginx.conf

nginxконфигурационный файл

🗄package.json

конфигурационный файл нпм

После завершения настройки структуры проекта предполагается, что вы уже находитесь вpackage.jsonВсе нужные нам зависимости сохранены в, попробуем набратьyarnдля установки зависимостей. Предполагая, что установка прошла успешно, давайте продолжим наш путь разработки.

Первый вpagesСоздайте новый под файломindex.js, здесь я просто случайным образом извлекаю какой-то код из своего реального проекта в качестве учителя.

export default class HomePage extends React.Component {
  static async getInitialProps({ req, pathname }) {
    const data = await fetch(`${ctx}/api/projects/common/list`).then(res => res.json())
    .then(dt => dt)
    .catch(err => {
      return {
        success: false,
        message: err.message
      }
    })
    return { pathname,data };
  }

  render() {
    const { pathname, data } = this.props;
    return (
      <div>
         <Head>
          <title>首页-易科捷(武汉)生态科技有限公司</title>
        </Head>
        <div>Welcome to next.js!</div>
    	{/*这里省略代码*/}
      </div>
    );
  }
}

если вашpackage.jsonне настроен вnextЗапустите скрипт, пожалуйста, посетитеsetupДля настройки ниже запускаем в консолиnpm run dev, если все в порядке, откройте браузер, и вы увидитеWelcome to next.js!

существуетnext.jsопыт разработки иreactпочти никакой разницы, но вwebpackНастройка этой части может занять немного работы. Некоторые часто используемые плагины, такие какsass,cssЖдать,next.jsВсе это предусмотрено для вас, и вы также можете использовать плагины сообщества с открытым исходным кодом, чтобы завершить свой путь разработки. Для получения подробной информации, пожалуйста, проверьтеофициальный сайт next.js.

развертывать

После прохождения ряда процессов, таких как этап разработки, тестирование и т. д., теперь, наконец, настал этап развертывания. существуетnext.jsНа стадии производства упаковка должна запускаться толькоnpm run buildВот и все, официальная рекомендация - не менять имя запакованной папки (оригинальное имя.next), вот я лично рекомендую модифицировать егоbuildилиdistэти имена. После того, как упаковка будет завершена, вам нужно написатьnodejsЗапустите файл записи и вставьте приведенный ниже пример кода:

const Koa = require('koa')
const next = require('next')
const Router = require('koa-router')

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 = new Koa()
    const router = new Router()
	// 首页
    router.get('/', async ctx => {
      await app.render(ctx.req, ctx.res, '/', ctx.query)
      ctx.respond = false
    })
	// 关于
    router.get('/about', async ctx => {
      await app.render(ctx.req, ctx.res, '/about', ctx.query)
      ctx.respond = false
    })
	// 产品
    router.get('/products/:id', async ctx => {
      const {id} = ctx.params
      await app.render(ctx.req, ctx.res, `/products/${id}`, ctx.query)
      ctx.respond = false
    })
	// 案例
    router.get('/case', async ctx => {
      await app.render(ctx.req, ctx.res, '/case', ctx.query)
      ctx.respond = false
    })
	// 联系我们
    router.get('/contact', async ctx => {
      await app.render(ctx.req, ctx.res, '/contact', ctx.query)
      ctx.respond = false
    })
	// 详情
    router.get('/view/:type/:id', async ctx => {
      const {id, type} = ctx.params
      await app.render(ctx.req, ctx.res, `/view`, {id, type})
      ctx.respond = false
    })
    // 如果没有配置nginx做静态文件服务,下面代码请务必开启
   /* router.get('*', async ctx => {
      await handle(ctx.req, ctx.res)
      ctx.respond = false
    })*/
    // 防止出现控制台报404错误
    server.use(async (ctx, next) => {
      ctx.res.statusCode = 200
      await next()
    })
    server.use(router.routes())
    server.listen(port, () => {
      console.log(`> Ready on http://localhost:${port}`)
    })
  })

Общие статические файлы, сжатие gzip не нужно передаватьnodejsЧтобы сделать это, я всегда думал, что профессиональные вещи оставляются профессиональным людям. Здесь задача передаетсяnginx, обратите особое внимание на часть кода, которую я прокомментировал в примере кода выше, если вы не используетеnginxЧтобы использовать статическую файловую службу, обязательно откройте ее, в противном случаеnext.jsупакованныйjs,css, файлы изображений и т. д., будут сообщены404.

существуетnext.jsУпаковано на стадии производственной упаковкиjsПуть запроса файла имеет номер версии, но фактическая упакованная папка не имеет фактического соответствующего каталога, то есть здесь используется упакованный виртуальный каталог.nginxнуждаются в особом внимании. к счастьюnext.jsУкажите элементы конфигурации для измененияbuild id, вот мой реальный код:

// next.config.js
module.exports = {
  generateBuildId: async () => {
    // For example get the latest git commit hash here
    return 'v1'
  }
}

Упакованный таким образом виртуальный путь, вероятно,_next/v1/page/xxx.js, если вы используетеcdnпрефикс, здесь есть небольшая разница, но номер версии все же есть.

Еще одно отверстиеnext.jsВ комплекте три папки:bundles,dist,static, для тех, кто не знает исходный код, они не знают, в какой папке находится фактический файл запроса. Так что я вижуnext.jsИсходный код, я обнаружил, что на самом деле я искалbundleпод файломpage, расположение исходного кода:L214

Итак, в конфигурацииnginxВам нужно использовать псевдоним. Ниже мой фрагментnginxРеальный код конфигурации:

		# 网站根目录文件
        location ~ ^/(robots.txt|humans.txt|favicon.ico|sw.js|baidu_verify_7Kj6tQjI3v.html) {
            root /home/website/eco_website_pc/static/;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        # static下的文件
        location ^~ /static/ {
            alias /home/website/eco_website_pc/static/;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        # next pages页面下的脚本
        location ~ ^/(/_next/v1/) {
            alias /home/website/eco_website_pc/build/bundles/;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        # next static下的静态文件
        location ~ ^/(/_next/static/) {
            root /home/website/eco_website_pc/build;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }

После того, как статический файл настроен, его необходимо настроитьhttpsСертификат в наличии, т.к. наш проект официальный сайт компании, сертификат получу бесплатно, вот пользуюсьfreesslСертификат целостности в Азии, представленный выше. После примененияsslПосле сертификата нужно перейти к провайдеру доменного имени для настройкиTXTДля справки, здесь я использую Alibaba Cloud.После завершения проверкиfreesslСертификат будет скачан, после получения сертификата необходимо его настроить.nginx sslСертификат, моя полная конфигурация размещена ниже:

server {
        listen       80;
        listen       443 ssl;
        server_name  wh-eco.com;
        charset utf-8;
        ssl_certificate /home/website/ssl/www/full_chain.pem;
        ssl_certificate_key /home/website/ssl/www/private.key;
        fastcgi_param   HTTPS               on;
        fastcgi_param   HTTP_SCHEME         https;

        if ($scheme = http ) {
          return 301 https://$host$request_uri;
        }
        access_log      /var/log/nginx/www.wh-eco.com.access.log;
        error_log       /var/log/nginx/www.wh-eco.com.error.log;
        location / {
            proxy_pass http://127.0.0.1:xxxx; #保密 0.0
            proxy_set_header Host $host;
            #proxy_redirect off;
            proxy_set_header    REMOTE-HOST $remote_addr;
        	# 网站可能后期会使用websocket 特次升级请求协议
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	        proxy_connect_timeout 60;
            proxy_read_timeout 600;
            proxy_send_timeout 600;
        }
        # 网站根目录文件
        location ~ ^/(robots.txt|humans.txt|favicon.ico|sw.js|baidu_verify_7Kj6tQjI3v.html) {
            root /home/website/eco_website_pc/static/;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        # static下的文件
        location ^~ /static/ {
            alias /home/website/eco_website_pc/static/;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        # next pages页面下的脚本
        location ~ ^/(/_next/v1/) {
            alias /home/website/eco_website_pc/build/bundles/;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        # next static下的静态文件
        location ~ ^/(/_next/static/) {
            root /home/website/eco_website_pc/build;
            if ($request_filename ~* sw.js){
                    expires -1s;
                }
            expires 10m;

	    }
        error_page   500 502 503 504 = /error.html;
        error_page  404 = /notfound.html;
        location = /error.html {
                root   /home;
            }
        location = /notfound.html{
            root  /home;
        }
    }

Что касаетсяgzipВы можете настроить его в соответствии с вашими требованиями, вставьте пример моей конфигурации:

 	gzip  on;
    gzip_comp_level 6;
    gzip_vary on;
    gzip_types
        application/atom+xml
        application/javascript
        application/json
        application/rss+xml
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        font/opentype
        image/svg+xml
        image/x-icon
        image/jpeg 
        image/gif 
        image/png
        text/css
        text/plain
        text/x-component;

по окончанииnginxЧто нужно сделать после настройкиpm2способ запуска всего приложения

pm2 start ecosystem.config.js

После выполнения вышеуказанной команды, если все пойдет хорошо, вы можете ввести доменное имя для доступа к вашему приложению (при условии, что вы завершили работу по разрешению доменного имени).

Суммировать

Как только вы входите в переднюю часть, она такая же глубокая, как море


Github | блог