В этой статье я покажу, как можно использовать один и тот же код на стороне клиента в javascript и на стороне сервера в pyhton.

Это возможно благодаря Haxe, языку, который может компилироваться на 8 языках (js, php, flash, python, java, c#, neko, c++).

В этом примере один и тот же шаблон рендерится на python и javascript с помощью Erazor, библиотеки шаблонов, а страницы обслуживаются с помощью flask.

вы можете найти код этого примера в этом репозитории github https://github.com/francescoagati/isomorphic-haxe-python.

Давайте посмотрим на отдельные части проекта.

build.hxml
В этом файле есть объявления для целей javascript и python, отделенные от аргумента next.
Для каждой цели есть путь к папке назначения, основному классу и библиотекам, которые должны быть включенным.

-js build/static/js/client.js
-main Client
-lib erazor
-dce full
-D analyzer
--next
-python build/server.py
-main Server
-lib erazor
-dce full
-D analyzer

аргумент dce используется для включения функции Устранение мертвого кода, которая позволяет исключить код, который не используется, а аргумент -D анализатор используется для включения статического анализатора для оптимизации кода.

article.html
Шаблон. Благодаря Erazor и макросам haxe шаблон преобразуется в код haxe и компилируется на целевой язык.

<h1>@title</h1>
<br>
<p>@body</p>

Template.hx
Класс для рендеринга шаблона.
Аннотация includeTemplate используется для определения пути к шаблону.

@:includeTemplate("templates/article.html")
class Template extends erazor.macro.HtmlTemplate {
  public var title:String;
  public var body:String;
}

Server.hx
Flask используется для обслуживания страниц.

Внешние haxe используются для сопоставления методов Flask с классом Haxe.

Маршрут на стороне сервера обслуживает страницу, скомпилированную в python, а маршрут на стороне клиента возвращает тег скрипта для выполнения кода javascript.

import haxe.Constraints.Function;
import python.KwArgs;
using python.Lib;


@:pythonImport("flask", "request")
  extern class Request implements Dynamic {
  public static var args:python.Dict<String,Dynamic>;
}


@:pythonImport("flask", "Flask")
extern class Flask {
  function new(module:String);
  function run(?opts:KwArgs<{?debug:Bool}>):Void;
  function route<T:Function>(path:String, ?opts:KwArgs<{?defaults:Dynamic}>):T->T;
}

class Server {
  public static function main() {

   var app = new Flask(untyped __name__);
   app.route("/server")(serverSide);
   app.route("/client")(clientSide);
   app.run();
  }


  static function clientSide() {
    return '
      <html>
        <body>
         <div id="content"></div>
          <script src="static/js/client.js"></script>
        </body>
      </html>

    ';
  }

  static function serverSide() {
    var template = new Template();
    template.title = "Hello from server side";
    template.body = "This content is rendered in python";
    return template.execute();
  }

}

Клиент.hx

Этот класс отображает шаблон ластика и вставляет вывод в div содержимого.

class Client {
  public static function main() {
    var template = new Template();
    template.title="Hello for client side";
    template.body="This content is rendered in javascript";
    js.Browser.document.getElementById('content').innerHTML = template.execute();
  }
}