关于前端:xzgztop网站开发记录

4次阅读

共计 3823 个字符,预计需要花费 10 分钟才能阅读完成。

xzgz.top 网站记录

次要技术栈

利用次要是由 koa 构建,其中 nextjs 只负责页面构建实现服务端渲染。以下是次要利用的技术

后盾

  • Koa:网站主题内容
  • koa-router:网站后端路由
  • koa-session:利用的 session 写入
  • nodemailer:发送邮件
  • mysql2:数据库操作
  • nodemon:开发模式下热更新
  • typescript
  • ts-node:实现开发模式下运行 ts 文件
  • tsconfig-paths:修复开发模式下 tsconfig.json 里门路映射在 ts-node 下不起作用。

前台

  • Nextjs:react 的服务端渲染
  • mobx:前端利用的全局状态治理
  • sass:前端利用的款式
  • github api:实现笔记贮存,及 markdown 文件转 html 性能

部署

  • 利用 github 的 webhook 进行自动化部署。
  • webhook 触发后执行 shell 脚本实现主动拉代码、docker 构建、运行利用。

    #!bin/sh
    
    exitError() {
    echo "---starting $1---"
    $1
    if [$? -eq 0]; then
      echo "---$1 successfully---"
    else
      echo "!!!!!!!!!!$1 error!!!!!!!!!!"
      exit 0
    fi
    }
    
    echo "==========starting rebuild=========="
    
    cd /root/xzgz
    
    exitError "git pull"
    
    exitError "docker build -t xzgz_i ."
    docker rm -f xzgz_i
    docker stop xzgz_c
    docker rm -f xzgz_c
    exitError "docker run -d -p 3000:3000 --name xzgz_c xzgz_i"
    
    echo "==========end rebuild=========="

遇到的一些问题

tsconfig.json 里门路映射问题

开发模式下
vscode 读取 tsconfig.json 里的门路映射没有问题,援用不会报错,然而 ts-node 启动脚本时会呈现门路映射失落的问题,解决办法是应用 tsconfig-paths:

# 应用以下命令开启脚本
npx ts-node -r tsconfig-paths/register --project ./tsconfig.json app_server/index.ts

在 nodemon 的配置文件 nodemon.json 里设置

{"watch": ["app_server/", "types/"],
  "ext": "js,json,ts",
  "execMap": {"ts": "ts-node -r tsconfig-paths/register --project ./tsconfig.json"}
}

生产模式下
间接应用 ts-node 启动服务器不适宜生产模式,应用 tsc 将 ts 文件编译成 js 文件进行运行。

tsc --project tsconfig.prod.json

生成的文件执行时和下面有同样的问题,因为 tsc 编译时不会对门路映射进行编译,间接执行会报错找不到模块。
依照 tsconfig-paths/register 的解决办法,在运行脚本之前对 Module.\_resolveFilename 进行重写,达到解析门路映射的问题。具体代码:

const Module = require("module");
const path = require("path");

// 具体的门路映射依据理论状况改变
const replaceUrl = /^@server\//;

function findModel(request, _module) {const pathArr = request.replace(replaceUrl, "");

  let i = _module;
  while (i) {const filename = path.resolve(i.path, "../");
    if (/app_server$/.test(filename)) {break;} else {i = _module.parent;}
  }

  return path.join(i.path, "../", pathArr);
}

function preRunApp() {
  var originalResolveFilename = Module._resolveFilename;

  Module._resolveFilename = function (request, _parent) {if (replaceUrl.test(request)) {const findModule = findModel(request, _parent);
      return originalResolveFilename.call(this, findModule);
    }
    return originalResolveFilename.call(this, request, _parent);
  };
}

preRunApp();

而后在执行脚本时应用命令

node -r ./preRunApp.js dist/app_server/index.js

应用 nodemailer 发送 163 邮箱时超时

nodemailer 应用 163 邮箱发邮件时遇到超时的问题,次要是因为应用 163 邮箱发送邮件时必须开启 secure:

transporter = nodemailer.createTransport({
  host: "smtp.163.com", // 第三方邮箱的主机地址
  port: 465, // 25/465, secure 为 true - 465;false - 25
  secure: true, // 163 邮箱必须为 true,outlook 邮箱必须为 false
  auth: {
    user: SENDER, // 发送方邮箱的账号
    pass: SMTP_CODE, // 邮箱受权明码
  },
});

生产环境申请工夫数据和开发环境申请同样的数据不统一(docker 容器和零碎时区不统一)

利用运行在 docker 容器中,docker 容器的日期和零碎的不统一。
在 Dockerfile 里配置将零碎应用时区拷贝进 docker 容器中,具体如下:

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' > /etc/timezone

生产环境申请接口的页面会报错,提醒水合失败,开发环境没有这个问题

这个问题也是由下面的问题影响的。docker 容器里 react 的脱水执行生成工夫的太平洋工夫。而到了客户端注水的时候生成东 8 区工夫,导致服务端和客户端渲染不统一,因而报错。

nextjs 中应用 mobx 服务端和客户端数据无奈保持一致

因为 mobx 在服务端初始化时生成的数据没有被传到客户端,所以须要客户端也会实现一次初始化。某些页面须要提前在 store 里调用办法实现服务端渲染。
那么须要手动的实现 mobx 的注水过程(相似于服务端渲染的脱水注水)。应用如下办法解决:

// pages/_app.ts
function MyApp({
  Component,
  pageProps,
  store, // 重点
}: AppProps & {store: AppStore}) {
  // 注水
  const _defaultStore = initializeStore(store);
  return (<MyAppContext.Provider value={_defaultStore}>
      <WithLayout {...pageProps} store={_defaultStore} />
    </MyAppContext.Provider>
  );
}

MyApp.getInitialProps = async (appContext: AppContext) => {const { Component, ctx} = appContext;

  // 服务端实现初始化
  const store = initializeStore();
  ctx.store = store;

  let appProps = {};
  if (Component.getInitialProps) {appProps = await Component.getInitialProps(ctx);
  }

  return {pageProps: appProps, store};
};

// store/index.ts
class Store {
  this.user = null
  // ...
  // 补水
  hydrate(initState: Store) {Object.assign(this, initState);
  }
}


let store: Store;
function initializeStore(initDate?: Store): Store {enableStaticRendering(typeof window === "undefined");

  const _store = store ?? new Store();
  if (initDate) {_store.hydrate(initDate);
  }
  // 客户端渲染总是 new 一个新对象
  if (typeof window === "undefined") return _store;
  if (!store) store = _store;

  return _store;
}

export {initializeStore, store};

残余问题

当初 session 没有写入长久层,每次从新构建导致所有用户登录生效。

欢送大佬来我的网站留言,探讨问题。

正文完
 0