Our cms is build up as a multiple pages application.
For the frontend our project using webpack multi entries&multi outputs.eg.html
const entryConfig = {
header: "./app_fe/header/header.tsx",
left_menu: "./app_fe/left_menu/left_menu.tsx",
login: "./app_fe/login/login.tsx",
};
複製代碼
For the backend we using egg.js view rendering.eg.node
nunjucks: {
enable: true,
package: 'egg-view-nunjucks',
},
複製代碼
config.view = {
defaultViewEngine: 'nunjucks',
mapping: {
'.tpl': 'nunjucks',
},
};
複製代碼
await ctx.render('notfound.tpl', pageOpt);
複製代碼
It's almost a perfect and a stable structure but you know,we do have some problems.webpack
So here we gonna resolve the problems metioned above.git
The first thing is to seperate the business tpl files from base tpl files.why?As we wanna the business tpl files to be generated automatically,we don't wanna push these files to the git storage.All we need to care are the base tpl files.
Our base tpl files including:
1.base.tpl (for importing the base js library)
2.header.tpl and left_menu.tpl (for the basic layout)
3.login.tpl
4.user_data.tpl (it's gonna be replaced by cookies sooner or later)
5.template.tpl (template for generating other business tpl files),here's the structure of itgithub
{% extends "base.tpl" %}
{% block body %}
{% include "user_data.tpl" %}
{% include "header.tpl" %}
{% include "left_menu.tpl" %}
<span id="nemo-wrapper"></span>
<%= script %>
{% endblock %}
複製代碼
We put all the ** base tpl files** in the templates fold in the root directory.web
Why dont' we put'em under the like app/baseView files and import it in a relative path? like belowjson
{% extends "baseView/base.tpl" %}
複製代碼
check here you'll get the answer,cause Nunjuck can even not support relative path~~~~bash
here we use HtmlWebpackPlugin to generate the file,basing on the template.tpl we create files according to the key of entryConfig So here we got all our business files.cookie
for (const key of Object.keys(entryConfig)) {
//業務tpl
if (!templates.includes(key)) {
array.push(
new HtmlWebpackPlugin({
filename: `../../../view/${key}.tpl`,
templateParameters: {
script: getScripts(key)
},
template: "./templates/template.tpl",
chunks: []
})
);
}
}
複製代碼
What if in some business files we need to import some extra js library?
we define a extraScriptMap here,like the code show below,app_user need import firebasejs,so we can concat it by the getScripts function.app
const extraScriptMap = new Map().set("app_user", [
`<script src="https://www.gstatic.com/firebasejs/5.5.2/firebase-app.js"></script>`,
`<script src="https://www.gstatic.com/firebasejs/5.5.2/firebase-auth.js"></script>`
]);
//獲取頁面的完整script
const getScripts = key => {
let script = `<script src="/public/webpack/js/${key}.js"></script>`;
if (extraScriptMap.has(key)) {
script += extraScriptMap.get(key).join("");
}
return script;
};
複製代碼
besides the business file we also need to insert the base tpl files into the app/view folder.
const templates = [];
glob.sync("templates/*.tpl").forEach(filePath => {
const templateName = filePath.split("/")[1].split(".")[0];
templates.push(templateName);
});
//非業務tpl(header,left_menu,user_data,login)
for (const key of templates) {
//去掉template.tpl
if (Object.is(key, "template")) continue;
array.push(
new HtmlWebpackPlugin({
filename: `../../../view/${key}.tpl`,
template: `./templates/${key}.tpl`,
chunks: []
})
);
}
複製代碼
using glob we can find out all the files under templates folder.
As same as the buiness part , we push it into a HtmlWebpackPlugin and finally they are all insert into the app/view folder.
const htmlPluginArray = getHtmlPluginArray(entryConfig);
plugins: [
new ForkTsCheckerWebpackPlugin({
async: false,
tsconfig: "./tsconfig.json"
// tslint:'./tslint.json',
}),
// Ignore all locale files of moment.js
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
...htmlPluginArray
],
複製代碼
Till here , we solve the problem 1. For the problem 3 we just need to add a version or timestamp params after the script path.