項目重構記錄

項目最新一期需求變更比較大,恰好有時間作項目重構css

項目基本結構

原始項目結構爲html

-- config
-- pm2
-- app
 -- utils
 -- routes
 -- views
 -- src
 -- webpack
複製代碼
文件夾 含義
config 基本信息配置,好比鏈接數據庫等
pm2 項目部署到服務器
app 項目前端 + server

核心框架 koa react webpack3前端

後期重構以後,其目錄爲node

-- dist
-- server
  -- config
  -- utils
  -- router
  -- app.ts
-- pm2
-- src
  -- project
  -- webpack
  -- utils
複製代碼
文件夾 含義
server server
dist server編譯以後的js代碼
pm2 項目部署到服務器
src 項目前端代碼

核心框架 koa routing-controllers sequelize webpack4mysql

server 端

以前搭建一個簡單的koa項目react

const koa = require('koa')
const Router = require('koa-router')
const app = new koa()
const bodyParser = require('koa-bodyparser')

// formData數據解析到ctx.request.body中
app.use(bodyParser())
// 處理靜態資源
app.use(require('koa-static')(staticPath, { gzip: true }))

let user = new Router()
user.get('/users', async (ctx) => {
  ctx.body = 'get all users'
})

app.use(user.routes()).use(user.allowedMethods())

app.listen(3200, () => {
  console.log('3200')
})

複製代碼

加入 routing-controller 庫webpack

routing-controllers

routing-controllers --- 使用ts構建的一個幫助很方便處理router的框架git

createKoaServer

建立服務es6

import "reflect-metadata"; 
import { createKoaServer } from "routing-controllers";
import {UserController} from "./UserController";

const app = createKoaServer({
   controllers: [UserController] 
})

app.listen(3000, () => {
  console.log('the port is 3000')
})
複製代碼

簡單能夠理解爲建立了一個 koa 實例github

源碼

function createKoaServer(options) {
    var driver = new KoaDriver_1.KoaDriver();
    return createServer(driver, options);
}
複製代碼
useKoaServer

這也是一個經常使用的方法

當已經建立了 koa 實例, 能夠直接使用 useKoaServer 進行router注入

import "reflect-metadata"; 
import Koa from 'koa'
import { useKoaServer } from 'routing-controllers'
const app = new Koa()

useKoaServer(app, {
  controllers: [path.join(__dirname, '/controllers/*{.js,.ts}')],
})
console.log(app, 'app')
app.listen(3000, (e) => {
  console.log('the port is 3000', e)
})
複製代碼

源碼

function useKoaServer(koaApp, options) {
    var driver = new KoaDriver_1.KoaDriver(koaApp);
    return createServer(driver, options);
}
複製代碼

能夠看到二者中都用建立了一個 KoaDriver 的實例,只不過是傳參不一樣,後者將本身建立的koa實例做爲參數傳入函數內部了。

KoaDriver

核心代碼

class KoaDriver {
    constructor (koa, router) {
        super();
        this.loadKoa();
        this.loadRouter();
        this.app = this.koa;
    }
    
    // 在路由和中間件註冊以前 調用
    -- initialize ---
    initialize() {
        const bodyParser = require("koa-bodyparser");
        this.koa.use(bodyParser());
        if (this.cors) {
            const cors = require("kcors");
            if (this.cors === true) {
                this.koa.use(cors());
            } else {
                this.koa.use(cors(this.cors));
            }
        }
    }

    --- 註冊 routes ---
    registerRoutes() {
        this.koa.use(this.router.routes());
        this.koa.use(this.router.allowedMethods());
    }
    
    --- 生成 koa 實例 --- 
    loadKoa () {
        if (!this.koa) this.koa = new (require('koa'))()
    }
    
    --- router  --
    loadRouter () {
        if (!this.router) {
            this.router = new (require("koa-router"))()
        }
    }
    
    -- 註冊 Action --- 
    registerAction() {
        // -- something 沒看懂---
        
        const multer = this.loadMulter()
        
        
    }
} 
複製代碼
createExecutor
  • createServer
function createServer(driver, options) {
    createExecutor(driver, options);
    return driver.app;
}
複製代碼
  • createExecutor
function createExecutor (river, options) {
    -- something ----
    new RoutingControllers_1.RoutingControllers(driver, options)
        .initialize()
        .registerInterceptors(interceptorClasses)
        .registerMiddlewares("before", middlewareClasses)
        .registerControllers(controllerClasses)
        .registerMiddlewares("after", middlewareClasses);
}
複製代碼
  • RoutingControllers
class RoutingControllers {
    -- something ----
    initialize() {
     // -- 調用了上面的 initialize 方法 -- 添加 koa-bodyparser 中間件
        this.driver.initialize(); 
        return this;
    }
    
    -- something ----
    registerControllers () {
        this.driver.registerAction(...)
    }
}
複製代碼
other
  • 關於 render 頁面 --- 不能使用 @render
@Get('/')
  @Render('index')
  async index (
    @HeaderParam('device') device: string
  ) {
    console.log('device')
    return {
      title: 'i am title'
    }
  }
複製代碼

這樣寫了以後 後面的代碼就沒法運行了

同事有提出這個問題

處理方案

const body = fs.readFileSync(path.resolve('dist', 'index.html'), 'utf-8') 
    return body
  
    // --- 或者是 ----
    const htmlPath = path.resolve(process.cwd(), 'src/public/index.html')
    // 模板殷切使用 handlebars 
    return cons.swig(htmlPath, {
      title: 'Blued',
      config
    })
複製代碼
  • 關於處理 post 請求

以前的項目使用了 koa-bodyparser 來解析post請求的數據將其掛載在 ctx.body

若是涉及到文件上傳,還須要添加中間件 koa-multer 作處理

能夠考慮使用 Koa-body

參考文章

而routing-controllers 內部已經封裝了 koa-bodyparser 和 koa-multer 能夠直接使用

好比若是上傳文件

upload

以form-data格式進行上傳

@Controller()
export class UserController {
    @Post('/upload')
    test (
      @Body() body
      @UploadedFile('file') file
    ) {
        console.log('body', body)
        return {
          code: 200,
          data: body,
        }
    }
}
複製代碼

若是隻是post發送普通數據

post

@Post('/test')
    test (
      @Body() body
    ) {
        return {
          code: 200,
          data: body,
        }
    }
複製代碼

若是以form-date格式發送普通數據,沒有配合 @UploadedFile 則在Body上就沒法拿到數據

sequelize

sequelize入門篇

前端

能夠直接運行.ts文件

webpack

webpack + ts

ts版本的webpack配置基本安裝官網搭建

server

須要安裝 @types/webpack-dev-server

webpack -> v4

v3升級到v4,比較明顯的變化是一些插件已被廢棄或者已經變動了使用方式

  • hot屬性

在webpack4中 webpack-dev-server的 hot 屬性已經被廢棄了

devServer: {
    contentBase: path.join(__dirname, 'dist'),
    compress: true,
    host: 'localhost',
    hot: true,
    inline: true,
    port: 7777,
    before: function (app) {
      console.log('devserver')
    }
  },
複製代碼

將 hot 屬性刪除

能夠直接配置在命令中

"dev": "webpack-dev-server --open --hot --config webpack.dev.js --mode development"
複製代碼
  • 模塊找不到

解決方案 webpack - reaolve

extensions: ['.ts', '.tsx', '.json'], 
複製代碼

調整爲

extensions: ['.ts', '.tsx', '.json', 'js'], 
複製代碼
  • extract-text-webpack-plugin

使用 extract-text-webpack-plugin 來拆分css

可是一直在報錯

參考 issue

安裝

npm install --save-dev extract-text-webpack-plugin@next
複製代碼

或者更換爲 mini-css-extract-plugin

這個使用起來更加方便

{
  test: /\.s?css$/,
  use: [MiniCssExtractPlugin.loader,'css-loader', 'postcss-loader', 'sass-loader']
}

------

new MiniCssExtractPlugin({
  filename: "[name].css",
  chunkFilename: "[id].css"
})

複製代碼
  • UglifyjsWebpackPlugin

V4 中將 壓縮代碼的邏輯放到 optimization中了

optimization{
    minimize: isPro, // 是否進行代碼壓縮
    minimizer: [
      new UglifyjsWebpackPlugin()
    ]
}
複製代碼

將代碼進行壓縮,可是在控制檯會報錯

optimization

是由於 UglifyjsWebpackPlugin 沒法處理es6 語法

看下 tsx文件編譯使用的是 ts-loader,加入 babel-loader 處理

{
        test: /\.tsx?$/,
        include: /src/,
        // use: ['babel-loader'],
        use: ['babel-loader','ts-loader'],
        // use: ['ts-loader'],
        exclude: /node_modules/
      },
複製代碼

或者更換壓縮代碼的庫 terser-webpack-plugin

optimization {
    minimize: true, // 是否進行代碼壓縮
    minimizer: [
      new TerserPlugin({....})
    }
}
複製代碼
  • 使用 image-webpack-loader 致使項目中雪碧圖在iOS中加載失敗

項目測試中發現,在iOS手機中,編譯的雪碧圖一直讀取失敗。在Safari中打開頁面,也是有問題的。

img

這個資源是存在的

error

可是一個很是奇怪的問題,就是本地沒法打開

local

右鍵使用Safari直接打開 也沒法展現圖片

能夠看到直接從磁盤中打開都沒法讀取圖片信息

info

因此確定是講過webpack編譯以後的圖片出現了問題

而後嘗試關閉雪碧圖,直接使用base64格式展現,仍然失敗。

後來查看webpack關於圖片的配置,有一個處理圖片的loader -》image-webpack-loader

這個是用來減小圖片大小的,

插件的issure中有提到這個問題 click me

issure

這個插件使用示例有一個 webp 參數

webp: {
        quality: 75,
    }
複製代碼

這個參數一旦開啓,會把全部的圖片先轉爲 webp 的格式 格式轉化會致使在iOS中展現失敗 因此要關閉這個參數

  • dom7??

dom7

rules: [
    {
      test: /\.js$/, // Check for all js files
      exclude: /node_modules\/(?!(dom7|swiper)\/).*/,
      loader: 'babel-loader'
    }
]
複製代碼
  • babel

babel配置變更 @babel/xxx

{
  "presets": ["@babel/preset-env"]
}
複製代碼

babel && babel-polyfill

項目上線以後,有用戶反饋在安卓低版本(安卓 4.x 左右) 中出現白屏問題

發現是代碼中的一些API沒有被支持,查閱問題後,解決方案是引入 babel-polyfill

1 在頁面頭部直接引入

import 'babel-polyfill'
複製代碼

2 調整webpack的入口文件

entry: {
      Vendor,
      index: ['babel-polyfill', `./project/${project}/index.tsx`]
    },
複製代碼

3 調整 babel 配置

plugin: ["@babel/plugin-transform-runtime"]
複製代碼

原本覺得 babel 自己是能夠處理各類兼容問題,原來不是這樣的, babel只是會編譯語法,對於代碼中使用的API是不會作處理的

let newAry = [...1, 2,  3.2, 3],map((it) => Number.isFinite(it))
複製代碼

babel

若是所示,babel 並無將es6的 isFinite 這個API轉爲ES5的方法實現

然而在低版本中 有多是不支持 isFinite 這個方法的,可能致使問題,因此須要藉助 polyfill 來處理

參考文章

相關文章
相關標籤/搜索