在前端開發過程中,我們需要在開發過程中,將開發中的站點部署到服務器上,然后,在瀏覽器中查看實際的效果,在 Grunt 環境下,可以直接使用集成在 Grunt 中的 Connect 插件完成站點服務器的支持,在開發過程中,直接查看效果。
1. Connect 資源
與 Grunt 集成的 Connect 可以在 GitHub 上找到,地址:https://github.com/gruntjs/grunt-contrib-connect
安裝的時候,直接通過 NPM 就可以,不用自己下載。執行下面的命令將 grunt-contrib-connect 安裝到你的項目中。
npm install grunt-contrib-connect --save-dev
安裝之后,需要在你的 Gruntfile.js 項目文件中,加載這個插件。
grunt.loadNpmTasks('grunt-contrib-connect');
具體的配置信息見下一步了。
2. 基本配置
在你的 Gruntfile.js 中,添加一個 connect 的配置節。
在 connect 中設置一個 connect 任務的名字,注意不要叫 options ,這是 connect 保留的配置名。我們這里稱為 server。
完成之后的 Gruntfile.js 文件如下:
'use strict'; module.exports = function (grunt) { // Project configuration. grunt.initConfig({ connect: { server: { options: { port: 8000, hostname: '*', base: ['src/'] } } } }); grunt.loadNpmTasks('grunt-contrib-connect'); }
這里的配置是說服務器將工作在 8000 端口,網站的根目錄映射到物理目錄的 src/ 中。
我們可以在 src 中創建一個名為 index.html 的網頁,進行測試。
保存配置文件之后,在命令行執行 grunt connect
PS C:\study\grunt> grunt connect Running "connect:server" (connect) task Started connect web server on http://localhost:8000 Done, without errors.
在執行 Grunt 的過程中,網站服務器將會啟動,你可以通過瀏覽器來訪問這個服務器。但是,在 grunt 執行完成之后,服務器將會被自動關閉。所以,你可能根本來不及切換到瀏覽器去訪問你的頁面。
使用 keepalive 這個選項可以使得 grunt 在執行到 connect 的時候,不會退出這個任務,保持服務器的持續執行,這樣你就可以一直訪問這個服務器了。但是,需要注意的是,這個 grunt 任務會阻塞后繼任務的執行,所以,你需要將這個任務排在最后一個任務。
'use strict'; module.exports = function (grunt) { // Project configuration. grunt.initConfig({ connect: { server: { options: {
protocol: 'http', port: 8000, hostname: '*', keepalive: true, base: ['src/'] } } } }); grunt.loadNpmTasks('grunt-contrib-connect'); }
這個時候,重新執行 grunt connect 就會看到 Waiting forever... 的輸出,直到你 Ctrl+C 終止這個任務,grunt 會一直停留在 connect 這個任務上。
PS C:\study\grunt> grunt connect Running "connect:server" (connect) task Waiting forever... Started connect web server on http://localhost:8000 ^CTerminate batch job (Y/N)? y
在這一步,我們配置了如下的服務器參數:
- protocol 服務協議,可以是 'http' 或者 'https', 如果使用 https ,需要額外配置服務器證書。
- port 服務器的端口,默認為 8000
- base 可以是一個字符串,或者一個數組,或者一個對象,用來表示映射到網站虛擬根目錄的目標。
- 字符串,映射到網站虛擬根目錄的物理路徑,默認為 Gruntfile.js 所在的目錄
- 數組,多個被映射到網站虛擬根目錄的物理路徑
- 對象,每個路徑可以配置更加詳細的選項,可以通過 { path: xxx, options: xxxx} 進行配置,其中 options 會傳遞給 serve-state 模塊處理。
- hostname 默認為 '0.0.0.0',表示可以從任何網絡地址來訪問。
- keepalive 是否保持服務,不會退出服務
3. 高級配置
1. open
如果你希望在啟動服務之后,自動打開瀏覽器,而不用自己打開瀏覽器,再輸入訪問地址,可以將 open 設置為 true。
open 可以設置 boolean, 字符串,對象。
默認為 false,設置為 true 將會自動打開瀏覽器。
如果設置為字符串,則為瀏覽器打開的地址。
對象的配置將會直接傳遞給 open 處理。
{ target: 'http://localhost:8000', // target url to open, 目標路徑 appName: 'chrome', // name of the app that opens, ie: open, start, xdg-open,自動啟動的應用名稱, 比如你的瀏覽器:chrome callback: function() {} // called when the app has opened }
2. livereload
可以配置為 boolean 或者 數值,用來表示是否支持 livereload。
設置為 true 或者數值表示支持 connect-livereload,但是這個設置不能直接使用,需要 connect-livereload 的配合,所以並不能直接實現自動加載。你還需要 grunt-contrib-watch 或者其他的庫支持來實現文件修改時的自動加載。
下一次我們將會介紹這個 livereload 的使用。
3. useAvailablePort
如何使用端口,如果設置為 true,則任務會尋找 port 指定的下一個可用的端口,默認為 false.
4. onCreateServer
服務創建之后的回調函數,允許集成其它庫到網站中,例如,集成 Socket.IO 的示例。注意,這需要你先准備好了 socket.io 模塊。
grunt.initConfig({ connect: { server: { options: { port: 8000, hostname: '*', onCreateServer: function(server, connect, options) { var io = require('socket.io').listen(server); io.sockets.on('connection', function(socket) { // do something with socket }); } } } } });
5. middleware
很顯然,網站處理的中間件。如果你覺得這個默認的靜態文件服務器不夠強大的話,可以通過中間件進行擴展。
可以配置一個函數或者數組,默認為使用 options.base 處理靜態文件和目錄瀏覽的數組。
如果提供了一個數組的話,就會取代默認的服務器處理,直接采用自定義的中間件進行處理,這需要我們完全定義服務器中的處理。
數組的示例
grunt.initConfig({ connect: { server: { options: { middleware: [ function myMiddleware(req, res, next) { res.end('Hello, world!'); } ], }, }, }, });
如果是函數的話,會自動添加默認的靜態文件處理中間件,再執行自定義的中間件函數。
函數的示例
grunt.initConfig({ connect: { server: { options: { middleware: function(connect, options, middlewares) { // inject a custom middleware into the array of default middlewares middlewares.unshift(function(req, res, next) { if (req.url !== '/hello/world') return next(); res.end('Hello, world from port #' + options.port + '!'); }); return middlewares; }, }, }, }, });
這部分的源碼如下:
// The middleware options may be null, an array of middleware objects, // or a factory function that creates an array of middleware objects. // * For a null value, use the default array of middleware // * For a function, include the default array of middleware as the last arg // which enables the function to patch the default middleware without needing to know // the implementation of the default middleware factory function var middleware; if (options.middleware instanceof Array) { middleware = options.middleware; } else { middleware = createDefaultMiddleware.call(this, connect, options); if (typeof(options.middleware) === 'function') { middleware = options.middleware.call(this, connect, options, middleware); } }
6. 多個服務器
可以配置多個服務器,需要注意的是,如果有一個服務器的 keepalive 設置為 true,就會阻塞其它的服務器。
// Project configuration. grunt.initConfig({ connect: { site1: { options: { port: 9000, base: 'www-roots/site1' } }, site2: { options: { port: 9001, base: 'www-roots/site2' } } } });
7. HTTPS
使用 https 協議需要預先進行證書的配置。
如果沒有證書的話,可以使用 OpenSSL 創建自簽名的證書作為本地的根證書。
### Create ca.key, use a password phrase when asked ### When asked 'Common Name (e.g. server FQDN or YOUR name) []:' use your hostname, i.e 'mysite.dev' openssl genrsa -des3 -out ca.key 1024 openssl req -new -key ca.key -out ca.csr openssl x509 -req -days 365 -in ca.csr -out ca.crt -signkey ca.key ### Create server certificate openssl genrsa -des3 -out server.key 1024 openssl req -new -key server.key -out server.csr ### Remove password from the certificate cp server.key server.key.org openssl rsa -in server.key.org -out server.key ### Generate self-siged certificate openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
而 Gruntfile.js 中則需要進行相應的配置。
// Project configuration. grunt.initConfig({ connect: { server: { options: { protocol: 'https', port: 8443, key: grunt.file.read('server.key').toString(), cert: grunt.file.read('server.crt').toString(), ca: grunt.file.read('ca.crt').toString() }, }, }, });
如果你已經看到這里,你應該可以使用 grunt 創建一個開發中的測試服務器。