В этой статье я покажу, как можно использовать один и тот же код на стороне клиента в 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(); } }