Egg 靜態(tài)資源

2020-02-06 14:12 更新

egg-view-assets 提供了通用的靜態(tài)資源管理和本地開發(fā)方案,有如下功能

  1. 一體化本地開發(fā)方案
  2. 生產(chǎn)環(huán)境靜態(tài)資源映射
  3. 和模板引擎集成
  4. 約定下可使用多種構(gòu)建工具,如 webpack、roadhog、umi 等

可以先查看示例

頁面渲染

可通過自動(dòng)或手動(dòng)的方式添加靜態(tài)資源,以下有兩種方式

使用 assets 模板引擎

assets 模板引擎并非服務(wù)端渲染,而是以一個(gè)靜態(tài)資源文件作為入口,使用基礎(chǔ)模板渲染出 html,并將這個(gè)文件插入到 html 的一種方式,查看使用 roadhog 的例子

配置插件

// config/plugin.js
exports.assets = {
enable: true,
package: 'egg-view-assets',
}

配置 assets 模板引擎

// config/config.default.js
exports.view = {
mapping: {
'.js': 'assets',
},
};

添加靜態(tài)資源入口文件 app/view/index.js,然后調(diào)用 render 方法進(jìn)行渲染

// app/controller/home.js
module.exports = class HomeController extends Controller {
async render() {
await this.ctx.render('index.js');
}
}

渲染的結(jié)果如下

<!doctype html>
<html>
<head>
<link rel="stylesheet" rel="external nofollow" target="_blank" ></link>
</head>
<body>
<div id="root"></div>
<script src="http://127.0.0.1:8000/index.js" rel="external nofollow" ></script>
</body>
</html>

注意:這個(gè)路徑生成規(guī)則是有映射的,如 index.js -> http://127.0.0.1:8000/index.js。如果本地開發(fā)工具不支持這層映射,比如自定義了 entry 配置,可以使用其他模板引擎。

全局自定義 html 模板

一般默認(rèn)的 html 無法滿足需求,可以指定模板路徑和模板引擎。

// config/config.default.js
module.exports = appInfo => ({
assets: {
templatePath: path.join(appInfo.baseDir, 'app/view/template.html'),
templateViewEngine: 'nunjucks',
},
});

添加模板文件

<!doctype html>
<html>
<head>
{{ helper.assets.getStyle() | safe }}
</head>
<body>
<div id="root"></div>
{{ helper.assets.getScript() | safe }}
</body>
</html>

egg-view-assets 插件提供了 helper.assets 根據(jù)自己的場(chǎng)景調(diào)用,helper.assets.getScript() 可以不用傳參,會(huì)將 render 函數(shù)的參數(shù)透?jìng)鳌?/p>

頁面自定義 html 模板

支持根據(jù)不同頁面指定模板,可以在 render 方法傳參

// app/controller/home.js
module.exports = class HomeController extends Controller {
async render() {
await this.ctx.render('index.js', {}, {
templatePath: path.join(this.app.config.baseDir, 'app/view/template.html'),
templateViewEngine: 'nunjucks',
});
}
}

修改靜態(tài)資源目錄

以上例子是將靜態(tài)資源放到 app/view 目錄下,但大部分情況希望放到獨(dú)立目錄,如 app/assets。因?yàn)?assets 模板引擎使用 egg-view 的加載器,所以直接修改其配置

// config/config.default.js
module.exports = appInfo => ({
view: {
// 如果還有其他模板引擎,需要合并多個(gè)目錄
root: path.join(appInfo.baseDir, 'app/assets'),
},
});

使用其他模板引擎

如果無法滿足文件映射,可以配合其他模板引擎使用,這時(shí)不需要配置 assets 模板引擎,查看使用 umi 的例子。

// config/config.default.js
exports.view = {
mapping: {
'.html': 'nunjucks',
},
};

渲染模板

// app/controller/home.js
module.exports = class HomeController extends Controller {
async render() {
await this.ctx.render('index.html');
}
}

添加模板文件(簡化了 umi 的模板)

<!doctype html>
<html>
<head>
{{ helper.assets.getStyle('umi.css') | safe }}
</head>
<body>
<div id="root"></div>
{{ helper.assets.getScript('umi.js') | safe }}
</body>
</html>

在其他模板中必須添加參數(shù)生成需要的靜態(tài)資源路徑

上下文數(shù)據(jù)

有時(shí)候前端需要獲取服務(wù)端數(shù)據(jù),所以在渲染頁面時(shí)會(huì)向 window 全局對(duì)象設(shè)置數(shù)據(jù)。

assets 模板引擎可直接傳入?yún)?shù),默認(rèn)前端代碼可以從 window.context 獲取數(shù)據(jù)。

// app/controller/home.js
module.exports = class HomeController extends Controller {
async render() {
await this.ctx.render('index.js', { data: 1 });
}
}

其他模板引擎需要調(diào)用 helper.assets.getContext(__context__) 并傳入上下文的參數(shù)

// app/controller/home.js
module.exports = class HomeController extends Controller {
async render() {
await this.ctx.render('index.html', {
__context__: { data: 1 },
});
}
}

默認(rèn)屬性為 context,這個(gè)可以通過配置修改

exports.assets = {
contextKey: '__context__',
};

構(gòu)建工具

這種模式最重要的是和構(gòu)建工具整合,保證本地開發(fā)體驗(yàn)及自動(dòng)部署,所以構(gòu)建工具和框架需要有一層約定。

下面以 roadhog 為例

映射關(guān)系

構(gòu)建工具的 entry 配置決定了映射關(guān)系,如基于 webpack 封裝的 roadhog、umi 等工具內(nèi)置了映射關(guān)系,如果單獨(dú)使用 webpack 需要根據(jù)這層映射來選擇用哪種方式。

  • 文件源碼 app/assets/index.js,對(duì)應(yīng)的 entry 為 index.js
  • 本地靜態(tài)服務(wù)接收以此為 entry,如請(qǐng)求 http://127.0.0.1:8000/index.js
  • 構(gòu)建生成的文件需要有這層映射關(guān)系,如生成 index.{hash}.js 并生成 manifest 文件描述關(guān)系如{ "index.js": "index.{hash}.js"}

roadhog 完全滿足這個(gè)映射關(guān)系使用 assets 模板引擎。而 umi 不滿足文件映射,因?yàn)樗挥幸粋€(gè)入口 umi.js 文件,所以選擇其他模板引擎的方案。

其他構(gòu)建工具的接入需要滿足這層映射關(guān)系。

本地開發(fā)

查看示例配置,本地服務(wù)配置成 roadhog dev,配置 port 來檢查服務(wù)是否啟動(dòng)完成,因?yàn)?roadhog 默認(rèn)啟動(dòng)端口為 8000,所以這里配置成 8000。

exports.assets = {
devServer: {
command: 'roadhog dev',
port: 8000,
},
};

部署

靜態(tài)資源部署之前需要構(gòu)建,配置 roadhog build 命令,并執(zhí)行 npm run build

{
"scripts": {
"build": "SET_PUBLIC_PATH=true roadhog build"
}
}

注意:這里添加了 SET_PUBLIC_PATH 變量是因?yàn)?roadhog 這樣才能開啟 publicPath

構(gòu)建的結(jié)果根據(jù) .webpackrc 配置的 output 決定,示例是放到 app/public 目錄下,由 egg-static 提供服務(wù)。

同時(shí)根據(jù) .webpackrc 配置的 manifest 生成一個(gè) manifest.json 文件到 config 目錄下(egg 需要讀取這個(gè)文件作為映射關(guān)系)。

應(yīng)用提供服務(wù)

現(xiàn)在應(yīng)用啟動(dòng)后可以通過 http://127.0.0.1:7001/public/index.{hash}.js 訪問靜態(tài)資源,發(fā)現(xiàn)這里多了一層 public 的路徑,所以需要添加 publicPath 配置。

// config/config.prod.js
exports.assets = {
publicPath: '/public/',
};

使用 CDN

一般靜態(tài)資源都會(huì)發(fā)到 CDN,所以在構(gòu)建完成后需要平臺(tái)將構(gòu)建產(chǎn)物發(fā)布到 CDN 上,如 https://cdn/myapp/index.{hash}.js。

現(xiàn)在除了 publichPath 還需要修改靜態(tài)資源地址

// config/config.prod.js
exports.assets = {
url: 'https://cdn',
publicPath: '/myapp/',
};


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)