成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

接了個(gè)新項(xiàng)目

stormgens / 487人閱讀

摘要:背景最近接了個(gè)新項(xiàng)目,遇到一些問題,在這整理分享下。你可能要問,既然可以不用配為什么你還要用呢可能是因?yàn)椋觽€(gè)看起來比較丑吧未完待續(xù),持續(xù)更新目前處于階段,主要功能開發(fā)完成,計(jì)劃號(hào)上測(cè)試,進(jìn)度上問題不大。

背景
最近接了個(gè)新項(xiàng)目, 遇到一些問題, 在這整理分享下。

前期規(guī)劃

需求是這樣的,需要做一套后臺(tái)管理系統(tǒng): 一個(gè)主系統(tǒng),一個(gè)子系統(tǒng),開發(fā)時(shí)間6個(gè)周。 前期開發(fā)有兩個(gè)人, 再加一個(gè)人。

說實(shí)話時(shí)間有點(diǎn)緊, 所以前期做好規(guī)劃就很重要。 實(shí)現(xiàn)先做一個(gè)規(guī)劃,技術(shù)選型,文檔分析,分頁面, 有個(gè)大致的評(píng)估。

技術(shù)選型

首先確定的還是 React 這一套, 即: React,Redux,TypeScript, 樣式管理 styled-components, 國(guó)際化 react-intl, 組件庫(kù) antd, 腳手架,自己配。 本來想圖省事用 CRA(create-react-app),后來覺得用rewired 重寫不太靈活, 而且有個(gè)小伙伴也想自己配,熟悉下 webpack , 還是決定自己搭, 后面會(huì)把配置貼出來。

開發(fā)計(jì)劃

和后端負(fù)責(zé)人討論之后決定把這一期的開發(fā)任務(wù)分成三個(gè)小階段: P1, P2, P3

P1 完成之后發(fā)布, 先跑通主流程,P2 P3 繼續(xù)迭代功能。

P1 主要包括:

開發(fā)環(huán)境搭建

test環(huán)境資源申請(qǐng)

Nginx 配置

主系統(tǒng)功能開發(fā)

三個(gè)功能模塊開發(fā)

登陸注冊(cè)流程

子系統(tǒng)兩個(gè)模塊的開發(fā)

開發(fā)時(shí)間: 兩周

壓力還是有的,時(shí)間緊,任務(wù)重,而且是第一次帶人做項(xiàng)目, 好在內(nèi)心猶如一條老狗,一點(diǎn)都不慌。

后面就進(jìn)入了開發(fā)階段, 遇到了挺多問題。

進(jìn)入開發(fā) 搭建開發(fā)環(huán)境

這一步大家就都很熟悉了,添加各種配置和打包。 因?yàn)橹飨到y(tǒng)和子系統(tǒng)頁面風(fēng)格都是一樣的, 沒必要分成兩個(gè)系統(tǒng), 把新開一個(gè)文件夾,里面放子系統(tǒng)的頁面, 然后打成不同的包就可以了。就有了如下配置:

// webpack.config.js

const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const webpack = require("webpack")
const fs = require("fs")
const lessToJS = require("less-vars-to-js")

const { NODE_ENV } = process.env

const isAdminApp = process.env.APP_TYPE === "admin"
const getBaseurl = () => {
  switch (process.env.ENV) {
    case "id":
      return "https://xxx.test.shopee.co.id"
    default:
      return ""
  }
}

const plugins = [
  new HtmlWebpackPlugin({
    template: path.resolve(__dirname, "template.html"),
    title: isAdminApp ? "WMS LITE ADMIN" : "WMS LITE",
  }),
  new webpack.DefinePlugin({
    __BASEURL__: JSON.stringify(getBaseurl()),
  }),
  new webpack.IgnorePlugin(/^./locale$/, /moment$/)
]
if (NODE_ENV !== "production") {
  plugins.push(new webpack.SourceMapDevToolPlugin({}))
}

const themeVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, "./assets/antd-custom.less"), "utf8"))

const port = isAdminApp ? 9527 : 8080

module.exports = {
  entry: [
    "@babel/polyfill",
    isAdminApp ? "./admin/index.js" : "./pages/index.js"
  ],
  output: {
    filename: isAdminApp ? "admin.[hash:8].js" : "main.[hash:8].js",
    path: path.resolve(__dirname, isAdminApp ? "dist/adminstatic" : "dist/static"),
    publicPath: isAdminApp ? "/admin/" : "/",
  },
  mode: NODE_ENV,
  devtool: false,
  plugins,
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /.less$/,
        use: [
          { loader: "style-loader", },
          { loader: "css-loader", },
          {
            loader: "less-loader",
            options: {
              javascriptEnabled: true,
              sourceMap: true,
              modifyVars: themeVariables,
            },
          }
        ],
      },
      {
        test: /.css$/,
        use: [
          { loader: "style-loader", },
          { loader: "css-loader", }
        ],
      },
      {
        type: "javascript/auto",
        test: /.mjs$/,
        use: [],
      },
      {
        test: /.(png|jpg|gif|svg)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 8192,
            },
          }
        ],
      }
    ],
  },
  optimization: {
    runtimeChunk: {
      name: "manifest",
    },
    splitChunks: {
      chunks: "all",
      minSize: 30000,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      cacheGroups: {
        vendor: {
          test: /[/]node_modules/,
          filename: "vendor.[chunkhash:8].js",
          enforce: true,
          priority: 5,
        },
        antd: {
          test: /[/]node_modules[/]antd[/]/,
          filename: "antd.[chunkhash:8].js",
          priority: 10,
        },
        antdIcons: {
          test: /[/]node_modules[/]@ant-design[/]/,
          filename: "antd-icons.[chunkhash:8].js",
          priority: 15,
        },
        styles: {
          test: /.(scss|css)$/,
          filename: "styles.[hash:8].css",
          minChunks: 1,
          reuseExistingChunk: true,
          enforce: true,
          priority: 20,
        },
      },
    },
  },
  devServer: {
    historyApiFallback: isAdminApp ? {
      rewrites: [{ from: /.*/g, to: "/admin/index.html", }],
    } : true,
    hot: true,
    port,
    proxy: [{
      context: ["/admin/api", "/api"],
      target: "https://gudangku.test.shopee.co.id",
      changeOrigin: true,
      onProxyRes(proxyRes, _, res) {
        const cookies = proxyRes.headers["set-cookie"] || []
        const re = /domain=[w.]+;/i
        const newCookie = cookies.map(cookie => cookie.replace(re, "Domain=localhost;"))
        res.writeHead(200, {
          ...proxyRes.headers,
          "set-cookie": newCookie,
        })
      },
    }],
  },
}
// package.json

  "scripts": {
    "start": "NODE_ENV=development APP_TYPE=main webpack-dev-server",
    "build": "NODE_ENV=production APP_TYPE=main webpack",
    "start:admin": "NODE_ENV=development APP_TYPE=admin webpack-dev-server",
    "build:admin": "NODE_ENV=production APP_TYPE=admin webpack",
    "lint": "eslint ./ --ext js",
    "i18n": "node i18n/index.js"
  },

根據(jù)不同的參數(shù)打包, 主系統(tǒng)打包到 dist/static, 子系統(tǒng)打包到dist/adminstatic.

解決完打包的問題, 還有另一個(gè)問題, 就是本地開發(fā)的時(shí)候需要配置代理。

目前比較通用的做法有:

devServer 配置 proxy

修改 host

Nginx 做反向代理

// 也可以說只有兩種。

我用的是1, 原因是比較靈活, 這個(gè)系統(tǒng)后面要發(fā)布到7個(gè)或者更多的國(guó)家, 改host 總歸是不太優(yōu)雅, 來回倒騰Nginx 又費(fèi)時(shí)費(fèi)力, 提個(gè)單大半天不批,不太方便。

后面又遇到的問題是登陸的時(shí)候需要請(qǐng)求一次csrftoken, 因?yàn)?domain 不匹配所以cookie 種不進(jìn)來, 所以就改了下配置,代碼見 devServer 部分,這個(gè)問題就解決了。

打包優(yōu)化

初步做了個(gè)優(yōu)化, 代碼分包, 這個(gè)系統(tǒng)antd 用的比較多,代碼體積, 和業(yè)務(wù)代碼打在一個(gè)包里明顯是不合適的,就簡(jiǎn)單分了一下:

壓縮后總體積900K。

FCP 1s, 勉強(qiáng)還能接受, 后面有需要再做優(yōu)化。

國(guó)際化實(shí)現(xiàn)
國(guó)際化用的是`react-intl`, 用起來就很簡(jiǎn)單了:

主要就兩種形式:

直接翻譯:

需要特殊傳, 比如 placeholder, Modal 的title等,如果直接用1 的方式會(huì)顯示一個(gè)[object Object] ,好在react-intl 提供了 injectIntl 方法可以解決這個(gè)問題:

 is a component which cannot be placed to placeholder which expects a raw String.

用法:

import {injectIntl} from "react-intl"; 

class TestComponent extends React.Component{
  render(){
    const { intl } = this.props;
    return (
        
    )
  }
}

export default injectIntl(TestComponent);

傳入的 id, 是你自己定義的,如果有翻譯平臺(tái)的話, 可以自己添加這些key:

在翻譯平臺(tái)完成翻譯后, 需要下載到本地, 需要手動(dòng)下載, 感覺很麻煩, 于是我就寫了個(gè)腳本來自動(dòng)下載, 翻譯平臺(tái)更新后, 執(zhí)行下 yarn i18n 就可以更新過來了:

頁面字段的替換就按上面的兩種方法, 純粹的體力活, 沒什么好說的。

Nginx 配置

功能開發(fā)完之后, 要發(fā)布到測(cè)試環(huán)境, 中間要配置Nginx, 我這有個(gè)配置平臺(tái), 加配置之后提單, 自動(dòng)部署。

配置的時(shí)候還是遇到一些問題的。

首先解決 index.html 訪問路徑的問題:

需要配置的路徑有:

/

/index.html

/admin

/admin/index.html

首先看 //index.html

還需要配置環(huán)境和地區(qū):

/admin/admin/index.html 也一樣的配置。

不過需要注意的是, //admin 需要配置 try_files :

/ :

/admin :

對(duì)應(yīng)生成的 conf 文件:

什么是try_files

從字面上理解就是嘗試文件,再結(jié)合環(huán)境理解就是嘗試讀取文件, 那是想讀取什么文件呢,讀取 靜態(tài)文件.

$uri, 這個(gè)是nginx的一個(gè)變量,存放著用戶訪問的地址. 比如:http://www.xxx.com/index.html, 那么$uri就是 /index.html

$uri/ 代表訪問的是一個(gè)目錄,比如:http://www.xxx.com/hello/test/, 那么$uri/就是 /hello/test/

完整的解釋就是:

try_files 去嘗試到網(wǎng)站目錄讀取用戶訪問的文件, 如果第一個(gè)變量存在,就直接返回;
不存在繼續(xù)讀取第二個(gè)變量,如果存在,直接返回;不存在直接跳轉(zhuǎn)到第三個(gè)參數(shù)上。

至于為什么要配try_files , 因?yàn)槲覀兊穆酚墒腔?b>browserHistory的, 如果用 hashHistory 就不用配 try_files。 你可能要問, 既然 hashHistory 可以不用配 try_files, 為什么你還要用browserHistory 呢?

可能是因?yàn)椋?加個(gè)/#/ 看起來比較丑吧 :)

未完待續(xù), 持續(xù)更新..

5.21 目前處于P3階段, 主要功能開發(fā)完成,計(jì)劃5.27號(hào)上測(cè)試,進(jìn)度上問題不大。 后面有什么值得分享的問題再說。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/114666.html

相關(guān)文章

  • 了個(gè)項(xiàng)目

    摘要:背景最近接了個(gè)新項(xiàng)目,遇到一些問題,在這整理分享下。你可能要問,既然可以不用配為什么你還要用呢可能是因?yàn)?,加個(gè)看起來比較丑吧未完待續(xù),持續(xù)更新目前處于階段,主要功能開發(fā)完成,計(jì)劃號(hào)上測(cè)試,進(jìn)度上問題不大。 背景 最近接了個(gè)新項(xiàng)目, 遇到一些問題, 在這整理分享下。 前期規(guī)劃 需求是這樣的,需要做一套后臺(tái)管理系統(tǒng): 一個(gè)主系統(tǒng),一個(gè)子系統(tǒng),開發(fā)時(shí)間6個(gè)周。 前期開發(fā)有兩個(gè)人, 再加...

    chaos_G 評(píng)論0 收藏0
  • 前端開發(fā)流程中一定要注意的5個(gè)點(diǎn)!

    摘要:作為一個(gè)老前端給新人們的一些關(guān)于開發(fā)流程上的建議拒絕和設(shè)計(jì)稿沒有封板就要求排期,和產(chǎn)品設(shè)計(jì)充分溝通。雙方還是要找到平衡點(diǎn)確保產(chǎn)品質(zhì)量和上線時(shí)間點(diǎn)的前提下,前端的開發(fā)難度和工作量是合理的。 作為一個(gè)老前端給新人們的一些關(guān)于開發(fā)流程上的建議 1. 拒絕PRD和設(shè)計(jì)稿沒有封板就要求排期,和產(chǎn)品設(shè)計(jì)充分溝通。 前端開發(fā)經(jīng)常會(huì)遇到這樣的情況,項(xiàng)目經(jīng)理莫名奇妙發(fā)了個(gè)會(huì)議邀請(qǐng),然后一股腦把產(chǎn)品下階段...

    王晗 評(píng)論0 收藏0
  • 程序員如何在996之外獲得收入

    摘要:因?yàn)榫W(wǎng)站建設(shè)一般項(xiàng)目比較小,我一個(gè)人是可以完成前后端開發(fā)的,如果做成成品當(dāng)然得加上小蘇設(shè)計(jì)師。關(guān)鍵詞選擇因?yàn)槊嫦虻氖菃蝹€(gè)城市業(yè)務(wù),在城市選擇上猶豫了不少時(shí)間,首先得是一個(gè)大城市,客戶量足,當(dāng)時(shí)我在北京,小蘇是在一個(gè)省會(huì)城市。 我技術(shù)之外的資本是零,如果你也是這樣,那這篇文章適合你! 這是我的故事之一,希望對(duì)你有啟發(fā)。如果你每天下班后就是躺在床上刷刷斗音,看看微博。但是又總想擺脫黑暗迷亂...

    siberiawolf 評(píng)論0 收藏0
  • 程序員如何在996之外獲得收入

    摘要:因?yàn)榫W(wǎng)站建設(shè)一般項(xiàng)目比較小,我一個(gè)人是可以完成前后端開發(fā)的,如果做成成品當(dāng)然得加上小蘇設(shè)計(jì)師。關(guān)鍵詞選擇因?yàn)槊嫦虻氖菃蝹€(gè)城市業(yè)務(wù),在城市選擇上猶豫了不少時(shí)間,首先得是一個(gè)大城市,客戶量足,當(dāng)時(shí)我在北京,小蘇是在一個(gè)省會(huì)城市。 我技術(shù)之外的資本是零,如果你也是這樣,那這篇文章適合你! 這是我的故事之一,希望對(duì)你有啟發(fā)。如果你每天下班后就是躺在床上刷刷斗音,看看微博。但是又總想擺脫黑暗迷亂...

    TZLLOG 評(píng)論0 收藏0
  • 程序員如何在996之外獲得收入

    摘要:因?yàn)榫W(wǎng)站建設(shè)一般項(xiàng)目比較小,我一個(gè)人是可以完成前后端開發(fā)的,如果做成成品當(dāng)然得加上小蘇設(shè)計(jì)師。關(guān)鍵詞選擇因?yàn)槊嫦虻氖菃蝹€(gè)城市業(yè)務(wù),在城市選擇上猶豫了不少時(shí)間,首先得是一個(gè)大城市,客戶量足,當(dāng)時(shí)我在北京,小蘇是在一個(gè)省會(huì)城市。 我技術(shù)之外的資本是零,如果你也是這樣,那這篇文章適合你! 這是我的故事之一,希望對(duì)你有啟發(fā)。如果你每天下班后就是躺在床上刷刷斗音,看看微博。但是又總想擺脫黑暗迷亂...

    YFan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<