註釋:如下內容只是『koa2-webpack-boilerplate』的說明文檔,算不得一篇文章,純粹我的的隨筆記錄。javascript
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
^6.0.0
^5.0.0
基於 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
安裝項目依賴成功後,啓動開發環境命令以下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 |
通常項目結構能夠按照文件類型
、功能類型
或其餘類型設計,每一個團隊每一個項目均可能會有本身的項目結構。 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 # 用於單元測試
咱們使用 webpack 對 app/assets/*
目錄下的文件進行動態編譯打包至 app/public/*
目錄下,經過 assetsMiddleware 中間件根據自動注入 bundle 文件。github
大體思路是:web
assets-webpack-plugin
生成 assetsMap.json
文件,而後根據 assetName
映射;ctx.state
上掛載 link
和 script
屬性,用於在 index.html
引用文件ctx.state.script = (assetName) => { return `<script src='${getUrlByEnv(assetName)}'></script>`; }; ctx.state.link = (assetName) => { return `<link rel='stylesheet' href='${getUrlByEnv(assetName)}'>`; };
應用圖片默認的位置是 app/assets 文件夾中的 images,經過相關配置會監聽並自動將圖片自動映射到 app/public 目錄下;
你能夠這樣引用圖片:
// in HTML <img src="images/egg_logo.svg" alt="logo">
// in SCSS background-image: url("images/egg_logo.svg");
推薦使用 SASS 進行樣式編寫;CSS 組織按照頁面(page)和框架(framework)進行區分自定義的和第三方庫的樣式,經過 @import
導入到 application.css
,目錄結構形如:
├── stylesheets | ├── page | | ├── homepage.csss | | └── help.scss | ├── framework | | ├── bootstrap.csss | | └── button.scss | ├── application.scss
應用按照功能模塊化進行開發,主要有如下兩種約定:
模塊化的幾種寫法:
方式一:掛載到 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 文件中,主要分爲如下幾個部分按照從上到下的順序處理的:
簡單演示約定
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-egg
規則;在開發模式下進行 eslint watching,它能夠有效的提示你對應的代碼是否符合約定規則。
pre-commit
是一個 git
的勾子,它能夠確保你在提交代碼前須要經過你預設的相關約定;在腳手架中主要用來確保在你提交代碼以前必須先經過全部的 Eslint
檢查,不然不能提交。
需求:如何在一個域名下根據項目名稱做爲前綴,同時掛載多個 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)
注意