亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

多頁架構(gòu)的前后端分離方案(webpack+express)

wums / 3196人閱讀

摘要:單頁架構(gòu)方案當(dāng)下雖然很時(shí)髦,不過大多數(shù)的網(wǎng)站依舊選擇多頁或者單頁多頁的混合架構(gòu)。在正式環(huán)境中直接配置進(jìn)行轉(zhuǎn)發(fā)補(bǔ)充本文拋磚引玉簡單搭建了一個(gè)前后端分離框架,但還有很多不完善的地方。

SPA(單頁架構(gòu))方案當(dāng)下雖然很時(shí)髦,不過大多數(shù)的網(wǎng)站依舊選擇多頁或者單頁+多頁的混合架構(gòu)。使用 express, webpack 本文低成本的實(shí)現(xiàn)了包含多頁架構(gòu),自動(dòng)刷新,前后端分離 等概念

先上項(xiàng)目

git repo
node-pages-webpack-hot

開發(fā)

 npm install
 npm install supervisor -g
 npm run start # 開發(fā)環(huán)境,配置 hot reload
 npm run prod # 生產(chǎn)環(huán)境
 npm run build # 編譯前端生產(chǎn)環(huán)境

DEMO

FE目錄:

SERVER目錄:

為了不浪費(fèi)你的時(shí)間,在閱讀以下內(nèi)容時(shí)需要有:

express 基礎(chǔ)知識(shí),以及對(duì) node 簡單了解

webpack 中級(jí)了解,本文采用 webpack2 實(shí)現(xiàn)

1. FE 端配置

前端配置需要實(shí)現(xiàn)的功能點(diǎn):

多頁架構(gòu)自動(dòng)生成 entry,并通過 html-webpack-plugin 生成每個(gè)頁面的模板,且選擇任意模板引擎需要實(shí)現(xiàn) layout 模板功能(本文使用swig作為模板引擎)

配置各種文件后綴的 loader

使用 HotModuleReplacementPlugin 實(shí)現(xiàn)修改自刷新

1.1 自動(dòng)分析entry

規(guī)定每個(gè)頁面必須有一個(gè)同名的 js 文件作為此頁面的 entry ,目錄深度可變,如下圖,分解為兩個(gè) entry:

為實(shí)現(xiàn)自動(dòng)化獲取,使用了 glob 獲取所有 .js 文件,并判斷是否有同名的 .html ,如果有則生成一個(gè) entry,如果是 dev 環(huán)境則多增加 hotMiddlewareScript 模塊

  // get all js files
  let files = glob.sync(config.src + "/**/*.js");
  let srcLength = config.src.length;

  let entrys = {};

  files.forEach(function (_file) {
    let file = path.parse(_file);
    let htmlFile = path.resolve(file.dir, file.name + "." + config.ext);

    // if has same name template file, it is a entry
    if (fs.existsSync(htmlFile)) {
      let pathIndex = file.dir.indexOf(config.src);

      if (config.dev == "dev") {
        entrys[config.staticRoot + file.dir.slice(srcLength) + "/" + file.name] = [path.resolve(_file), hotMiddlewareScript];
      } else {
        entrys[config.staticRoot + file.dir.slice(srcLength) + "/" + file.name] = path.resolve(_file);
      }
    }
  });

  return entrys;
1.2 自動(dòng)生成 html-webpack-plugin 模板

生成一系列 HtmlWebpackPlugin 的要點(diǎn)如下:

獲取到所有的 .html 后,判斷是否有對(duì)應(yīng)的 entry 文件,若有則創(chuàng)建 HtmlWebpackPlugin

如果頁面為 layout 模板,則需要多注入由 CommonsChunkPlugin 生成的 common 模塊

自動(dòng)生成 HtmlWebpackPlugin 代碼如下:

  let htmls = [];

  // get all templates
  let files = glob.sync(config.src + "/**/*." + config.ext);
  let srcLength = config.src.length;

  files.forEach(function (_file) {
    let file = path.parse(_file);

    let chunks = [];
    let chunkName = config.staticRoot + file.dir.slice(srcLength) + "/" + file.name;

    // if has same name entry, create a html plugin
    let c = entrys[chunkName];
    c && chunks.push(chunkName);

    // layout will contains common chunk
    if (file.name == config.serverLayoutName) {
      chunks.push(config.staticRoot + "/common");
    }

    let plugin = new HtmlWebpackPlugin({
      filename: config.templateRoot + file.dir.slice(srcLength) + "/" + file.base,
      template: path.resolve(file.dir, file.base),
      chunks: chunks,
      inject: false
    });

    htmls.push(plugin);
  });

  return htmls;

由于引入了模板 extends 支持,需設(shè)置 inject=false 便不會(huì)自動(dòng)注入 assets 文件

編寫 webpack 插件,將頁面的 js assets, css assets 分別注入到:


兩個(gè)替換文案處,例如頁面模板:

{% extends "../base/base.html" %}

{% block title %}My Page{% endblock %}

{% block style %}{%endblock%}

{% block head %}
  {% parent %}
{% endblock %}

{% block content %}

This is just an home page?。。?/p>

clouds
link page2 {% endblock %} {% block script %}{%endblock%}

編譯后替換后為:

{% extends "../base/base.html" %}

{% block title %}My Page{% endblock %}

{% block style %}{%endblock%}

{% block head %}
  {% parent %}
{% endblock %}

{% block content %}

This is just an home page?。?!

clouds
link page2 {% endblock %} {% block script %}{%endblock%}
1.3 各種 loader 配置,提取頁面 css

dev 環(huán)境下由于配置了 webpack-hot-middleware 所以不能對(duì) css 進(jìn)行提取,否則無法熱更新

樣式相關(guān)的 loader 配置如下:

var extractInstance = new ExtractTextPlugin("[name].css");

if (config.env == "dev") {
    var stylusLoader = [
      {
        loader: "style-loader"
      },
      {
        loader: "css-loader"
      },
      {
        loader: "stylus-loader"
      }
    ];

    var cssLoader = [
      {
        loader: "style-loader"
      },
      {
        loader: "css-loader"
      }
    ];
  } else {
    var stylusLoader = extractInstance.extract(["css-loader", "stylus-loader"]);
    var cssLoader = extractInstance.extract(["css-loader"]);
  }

并將所有的 loader 放到同一個(gè)文件進(jìn)行維護(hù):

  var rules = [
    {
      test: /.styl$/,
      exclude: /node_modules/,
      use: stylusLoader
    },
    {
      test: /.css$/,
      exclude: /node_modules/,
      use: cssLoader
    },
    {
      test: /.html$/,
      use: {
        loader: "html-loader",
        options: {
          minimize: false
        }
      }
    },
    ......
    ......
  ]
1.4 路徑配置

對(duì)生成模板,靜態(tài)文件輸出目錄進(jìn)行統(tǒng)一控制,便于結(jié)合各種后端架構(gòu)

const port = process.env.PORT || 8080;
const env = process.env.NODE_ENV || "dev";

const CONFIG_BUILD = {
  env: env,
  ext: "html", // tempate ext
  src: path.resolve(__dirname, "../src"), // source code path
  path: env == "dev" ? "/" : path.resolve(__dirname, "../dist"), // base output path
  templateRoot: "templates", // tempate output path
  staticRoot: "static", // static output path
  serverLayoutName: "base", // swig layout name , only one file
  publicPath: env == "dev" ? ("http://localhost:" + port + "/") : "/"
}
2. SERVER 端配置

server 端搭建了 express 服務(wù),實(shí)現(xiàn)的功能點(diǎn)如下:

使用 webpack-dev-middleware 進(jìn)行 webpack 編譯

使用 webpack-hot-middleware 實(shí)現(xiàn) hot reload

使用 supervisor 服務(wù)監(jiān)聽 node 文件改動(dòng)并自動(dòng)重啟

render 模板時(shí)將內(nèi)存中的文件寫入硬盤,以進(jìn)行渲染

2.1 webpack 接入 express

生成 webpackcompiler

  var webpack = require("webpack"),
    webpackDevConfig = require(path.resolve(config.root, "./fe/webpack.config.js"));

  var compiler = webpack(webpackDevConfig);

compiler 作為 express 的中間件

  // attach to the compiler & the server
  app.use(webpackDevMiddleware(compiler, {
    // public path should be the same with webpack config
    publicPath: webpackDevConfig.output.publicPath,
    noInfo: false,
    stats: {
      colors: true
    }
  }));

其中 publicPath 指明了 assets 請(qǐng)求的根路徑,這里配置的是:http://localhost:8080/

2.2 hot reload 方案 2.2.1 js,css 修改自刷新

js、css 的自刷新通過配置 webpack-hot-middleware 實(shí)現(xiàn)(fe 也需進(jìn)行相應(yīng)的配置)

  // server
  const webpackHotMiddleware = require("webpack-hot-middleware");
  app.use(webpackHotMiddleware(compiler));
  // fe
  webpackPlugins.push(
    new webpack.HotModuleReplacementPlugin()
  );
2.2.2 node 修改自刷新

node 文件修改通過配置 supervisor 服務(wù)實(shí)現(xiàn)自動(dòng)刷新

安裝服務(wù):

npm install supervisor -g

配置啟動(dòng)參數(shù):

// package.json
"scripts": {
  "start": "cross-env NODE_ENV=dev supervisor -w server -e fe server/server.js"
}

supervisor 監(jiān)聽了 server 文件夾下所有的改動(dòng),改動(dòng)后重啟 express服務(wù)。
想要實(shí)現(xiàn)瀏覽器自動(dòng)刷新,需要在 layout 模板加入如下代碼:

  {% if env == "dev" %}
    
  {% endif %}
2.3 對(duì) template 進(jìn)行 render

當(dāng) webpack 作為 express 中間件時(shí),生成的所有文件都存在內(nèi)存中,當(dāng)然也包括由 html-webpack-plugin 生成的模板文件。
然而 expressrender 函數(shù)只能指定一個(gè)存在于文件系統(tǒng)中的模板, 即dev 環(huán)境下 render 模板前需要將其從內(nèi)存中取得并存放到文件系統(tǒng)中。

module.exports = (res, template) => {
  if (config.env == "dev") {
    let filename = compiler.outputPath + template;
    // load template from 
    compiler.outputFileSystem.readFile(filename, function(err, result) {
      let fileInfo = path.parse(path.join(config.templateRoot, filename));


      mkdirp(fileInfo.dir, () => {
        fs.writeFileSync(path.join(config.templateRoot, filename), result);

        res.render(template);
      });
    });
  } else {
    res.render(template);
  }
}

layout 模板的存儲(chǔ)需要一個(gè)中間件:

  app.use((req, res, next) => {
    let layoutPath = path.join(config.templateRoot, config.layoutTemplate);
    let filename = compiler.outputPath + config.layoutTemplate;

    compiler.outputFileSystem.readFile(filename, function(err, result) {
      let fileInfoLayout = path.parse(layoutPath);

      mkdirp(fileInfoLayout.dir, () => {
        fs.writeFileSync(layoutPath, result);
        next();
      });
    });
  });

其余的均為 express 基礎(chǔ)使用,參閱文檔即可

2.4 代理后端接口

dev環(huán)境時(shí)使用 http-proxy-middleware 對(duì)后端接口進(jìn)行代理:

  // set proxy
  app.use("/api", proxy({target: config.proxy, changeOrigin: true}));

所有 /api 的請(qǐng)求都會(huì)代理到 config.proxy 配置的 ip 端口。

在正式環(huán)境中直接配置 nginx 進(jìn)行轉(zhuǎn)發(fā)

補(bǔ)充

本文拋磚引玉簡單搭建了一個(gè)前后端分離框架,但還有很多不完善的地方。真實(shí)的線上應(yīng)用還需要考慮 nodejs 運(yùn)維成本,日志,監(jiān)控等等。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86884.html

相關(guān)文章

  • webpack多頁應(yīng)用架構(gòu)系列(十五):論前如何在后渲染開發(fā)模式下夾縫生存

    摘要:回到純靜態(tài)頁面開發(fā)階段,讓頁面不需要后端渲染也能跑起來。改造開始本文著重介紹如何將靜態(tài)頁面改造成后端渲染需要的模板??偨Y(jié)在后端渲染的項(xiàng)目里使用多頁應(yīng)用架構(gòu)是絕對(duì)可行的,可不要給老頑固們嚇唬得又回到傳統(tǒng)前端架構(gòu)了。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/119000000820338...

    dinfer 評(píng)論0 收藏0
  • webpack多頁應(yīng)用架構(gòu)系列(十五):論前如何在后渲染開發(fā)模式下夾縫生存

    摘要:回到純靜態(tài)頁面開發(fā)階段,讓頁面不需要后端渲染也能跑起來。改造開始本文著重介紹如何將靜態(tài)頁面改造成后端渲染需要的模板??偨Y(jié)在后端渲染的項(xiàng)目里使用多頁應(yīng)用架構(gòu)是絕對(duì)可行的,可不要給老頑固們嚇唬得又回到傳統(tǒng)前端架構(gòu)了。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/119000000820338...

    dingda 評(píng)論0 收藏0
  • webpack多頁應(yīng)用架構(gòu)系列(十一):預(yù)打包Dll,實(shí)現(xiàn)webpack音速編譯

    摘要:本文首發(fā)于的技術(shù)博客實(shí)用至上,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載。原文地址如果您對(duì)本系列文章感興趣,歡迎關(guān)注訂閱這里前言書承上文多頁應(yīng)用架構(gòu)系列十如何打造一個(gè)自定義的。終于,發(fā)現(xiàn)了這一大殺器,打包時(shí)間過長的問題得到完美解決。 本文首發(fā)于Array_Huang的技術(shù)博客——實(shí)用至上,非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載。原文地址:https://segmentfault.com/a/119000000710437...

    sixleaves 評(píng)論0 收藏0
  • 架構(gòu) - 收藏集 - 掘金

    摘要:淺談秒殺系統(tǒng)架構(gòu)設(shè)計(jì)后端掘金秒殺是電子商務(wù)網(wǎng)站常見的一種營銷手段。這兩個(gè)項(xiàng)目白話網(wǎng)站架構(gòu)演進(jìn)后端掘金這是白話系列的文章。 淺談秒殺系統(tǒng)架構(gòu)設(shè)計(jì) - 后端 - 掘金秒殺是電子商務(wù)網(wǎng)站常見的一種營銷手段。 不要整個(gè)系統(tǒng)宕機(jī)。 即使系統(tǒng)故障,也不要將錯(cuò)誤數(shù)據(jù)展示出來。 盡量保持公平公正。 實(shí)現(xiàn)效果 秒殺開始前,搶購按鈕為活動(dòng)未開始。 秒殺開始時(shí),搶購按鈕可以點(diǎn)擊下單。 秒殺結(jié)束后,按鈕按鈕變...

    Riddler 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<