koa2 遇到 webpack 怎麼玩

『源代碼』

註釋:如下內容只是『koa2-webpack-boilerplate』的說明文檔,算不得一篇文章,純粹我的的隨筆記錄。javascript

Table of Contents

  1. Features
  2. Requirements
  3. Installation
  4. Running the Project
  5. Project Structure
  6. Live Developmentcss

  7. Routing
  8. Webpack
  9. Eslint
  10. Pre-commit
  11. Base Configuration
  12. In development Mode
  13. In production Mode
  14. Mount
  15. TODO

Features

This is a starter koa boilerplate app I've put together using the following technologies:html

koa v2
webpack v3
ES2015+
Babel
SCSS
Hot reload
Eslint
pre-commit
✓ ...java


Requirements

  • node ^6.0.0
  • npm ^5.0.0

Installation

基於 koa-boilerpate 開始一個新的項目node

$ git clone git@github.com:chenbin92/koa2-webpack-boilerplate.git MyApp
$ cd MyApp
$ npm install        # Install project dependencies listed in package.json

Running the Project

安裝項目依賴成功後,啓動開發環境命令以下jquery

// run the dev server http://localhost:3000
$ npm run dev:start

其餘任務腳本webpack

npm <script> Description
star:dev Serves your app in development mode
star:prod Serves your app in production mode
build Builds the application
lint Lints the project for potential errors

Project Structure

通常項目結構能夠按照文件類型功能類型或其餘類型設計,每一個團隊每一個項目均可能會有本身的項目結構。 koa2-webpack-boilerplate 奉行『約定優於配置』,按照一套統一的約定進行應用開發。git

koa2-webpack-boilerpate
├── index.js                        # 用於自定義啓動時的初始化工做(如配置babel-register)
├── src                             # 應用源代碼
|   ├── assets                      # 靜態資源
|   |   ├── images
|   |   ├── javascripts
|   |   └── stylesheets
|   ├── config                      # 用於編寫配置文件
|   |   └── dictionary.js
|   | 
│   ├── controller                  # 用於解析用戶的輸入,處理後返回相應的結果
│   |   └── home.js
│   ├── service                     # 用於編寫業務邏輯層
│   |   └── user.js
│   ├── middleware                  # 用於編寫中間件
│   |   └── response_time.js
│   ├── public                      # 惟一對外開放的文件夾,存放靜態文件和編譯後的資源文件
│   |   └── favicon.ico
│   ├── view                        # 用於放置模板文件
│   |   └── home.html
│   └── router                     # 用於配置 URL 路由規則
│   |   └── index.js
├── build                           # 用於編寫構建文件
|   ├── chalk.config.js
|   ├── project.config.js
|   └── webpack.prod.js
└── test                            # 用於單元測試

Live Development

HTML

咱們使用 webpack 對 app/assets/* 目錄下的文件進行動態編譯打包至 app/public/* 目錄下,經過 assetsMiddleware 中間件根據自動注入 bundle 文件。github

大體思路是:web

  • 在開發環境,直接使用webpack編譯在內存的文件系統做爲資源來源;
  • 在生產環境,先使用 assets-webpack-plugin 生成 assetsMap.json 文件,而後根據 assetName 映射;
  • ctx.state 上掛載 linkscript 屬性,用於在 index.html 引用文件
ctx.state.script = (assetName) => {
     return `<script src='${getUrlByEnv(assetName)}'></script>`;
 };

 ctx.state.link = (assetName) => {
      return `<link rel='stylesheet' href='${getUrlByEnv(assetName)}'>`;
    };

完整代碼

Images

應用圖片默認的位置是 app/assets 文件夾中的 images,經過相關配置會監聽並自動將圖片自動映射到 app/public 目錄下;

你能夠這樣引用圖片:

// in HTML
<img src="images/egg_logo.svg" alt="logo">
// in SCSS
background-image: url("images/egg_logo.svg");

StyleSheets

推薦使用 SASS 進行樣式編寫;CSS 組織按照頁面(page)和框架(framework)進行區分自定義的和第三方庫的樣式,經過 @import 導入到 application.css,目錄結構形如:

├── stylesheets
|   ├── page
|   |    ├── homepage.csss
|   |    └── help.scss
|   ├── framework
|   |    ├── bootstrap.csss
|   |    └── button.scss
|   ├── application.scss

JavaScript

  • 應用按照功能模塊化進行開發,主要有如下兩種約定:

    • Global Module: 掛載在 window 對象
    • Namespace: 掛載在 app 對象上
  • 模塊化的幾種寫法:

    • 方式一:掛載到 window 對象

      window.ModuleName = (function() {
        function Fn() {
          this.fn1();
        }
      
        Fn.prototype.fn1 = function() {}
      
        return Fn
      })();
    • 方式二:IIFE

      window.app = window.app || {};
      (function(app) {
        app.ModuleName = (function() {
          // your code...
        })();
      }).call(window, app);
      
      // or
      (function(global) {
        class ModuleName {
          // your code...
        }
      
        global.ModuleName = ModuleName
      })(window.appp || (window.app = {}));
    • 方式三:掛載到 app 對象上

      class ModuleName {
        // your code...
      }
      window.app = window.app || {};
      app.ModuleName = ModuleName;
    • 方式四: ES6 Class

      class ModuleName {
        constructor() {}
      
        fn() {}
      }
      export default ModuleName
    • 方式五: ...
  • 引用方式

在應用的 app/assets/javascripts/application.js 文件包含下面幾行代碼:

// import stylesheets
import '../stylesheets/application.scss';

// import page scripts
import './home';
import './about';

在應用的 app/assets/javascripts/vendors.js 文件包含下面幾行代碼:

// import Third-party libraries
import $ from 'jquery';
import _ from 'lodash';

在 JavaScript 文件中,主要分爲如下幾個部分按照從上到下的順序處理的:

  • 引入應用的樣式
  • 引入第三方庫
  • 引入業務模塊

Routing

簡單演示約定

import Router from 'koa-router';
import home from '../controller/home';
import about from '../controller/about';

const appRoutes = () => {
  // TODO: 添加前綴會致使靜態資源沒法加載
  const router = new Router({
    prefix: '/test',
  });

  router
    .get('/', home)
    .get('/about', about);

  return router;
};

export default appRoutes;

Eslint

項目遵循 eslint-egg 規則;在開發模式下進行 eslint watching,它能夠有效的提示你對應的代碼是否符合約定規則。

eslint watching


pre-commit

pre-commit 是一個 git 的勾子,它能夠確保你在提交代碼前須要經過你預設的相關約定;在腳手架中主要用來確保在你提交代碼以前必須先經過全部的 Eslint 檢查,不然不能提交。

pre-commit


Base configuration

  • Copy images
  • Sass compile
  • Generate html
  • Expose global
  • Define plugin
  • Assets webpack plugin

In Development mode

  • HOT
  • File watching
  • Eslint watching
  • Pre commit

In Production mode

  • Uglify javascript
  • Extract stylesheets
  • Extract the common file
  • Eslint watch
  • Bundle file analyzer
  • Static file md5

Mount

需求:如何在一個域名下根據項目名稱做爲前綴,同時掛載多個 web 應用。

例如:

根域名:http://www.upchina.com/

A 應用:http://www.upchina.com/A

B 應用:http://www.upchina.com/B

C 應用:http://www.upchina.com/C

解決方案:經過 Mount 解決,其思想是把整個應用看成一箇中間件,在 mount 內修改應用的 path,而後再次建立一個新的應用,將 mount 中間件傳遞

import Koa from 'koa'
import mount from 'mount'
import router from 'router'

// 傳遞給 mount 
const a = new Koa()
a.use(router().routes())

// app
const app = new Koa()
app.use(mount('/m', a))

app.listen(3001)

注意

  • 使用 Mount 只能用相對路徑
  • 能夠代理整個應用,也能夠只代理某個路由

推薦閱讀

相關文章
相關標籤/搜索