Как передать переменную из файла шаблона Jade в файл сценария? - PullRequest
109 голосов
/ 02 января 2012

У меня проблемы с переменной (config), объявленной в файле шаблона jade (index.jade), который не передается в файл javascript, что приводит к аварийному завершению работы моего javascript. Вот файл (views / index.jade):

h1 #{title}

script(src='./socket.io/socket.io.js')
script(type='text/javascript')
  var config = {};
  config.address = '#{address}';
  config.port = '#{port}';
script(src='./javascripts/app.js')

Вот часть моего app.js (на стороне сервера):

  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.set('address', 'localhost');
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
  res.render('index', {
    address: app.settings.address,
    port: app.settings.port
});
});

if (!module.parent) {
  app.listen(app.settings.port);
  console.log("Server listening on port %d",
app.settings.port);
}

// Start my Socket.io app and pass in the socket
require('./socketapp').start(io.listen(app));

А вот часть моего файла javascript, который дает сбой (public / javascripts / app.js):

(function() {
        var socket = new io.Socket(config.address, {port: config.port, rememberTransport: false});

Я запускаю сайт в режиме разработки (NODE_ENV = разработка) на локальном хосте (моя собственная машина). Я использую нод-инспектор для отладки, который сказал мне, что переменная config не определена в public / javascripts / app.js.

Есть идеи? Спасибо !!

Ответы [ 6 ]

155 голосов
/ 16 августа 2012

Это немного поздно, но ...

script.
  loginName="#{login}";

Это нормально работает в моем сценарии.В Экспрессе я делаю это:

exports.index = function(req, res){
  res.render( 'index',  { layout:false, login: req.session.login } );
};

Я думаю, что последний нефрит отличается от других?после сценария, чтобы предотвратить предупреждение Jade.

93 голосов
/ 04 февраля 2015

!{} для неэкранированного кода интерполяции, который больше подходит для объектов

script var data = !{JSON.stringify(data).replace(/<\//g, '<\\/')}

{ foo: 'bar' }
// becomes:
<script>var data = {"foo":"bar"}</script>

{ foo: 'bar</script><script>alert("xss")//' }
// becomes:
<script>var data = {"foo":"bar<\/script><script>alert(\"xss\")//"}</script>

Идея состоит в том, чтобы запретить атакующему:

  1. Вырваться из переменной: JSON.stringify экранировать кавычки
  2. Вырваться из тега сценария: если содержимое переменной (котороевы, возможно, не сможете контролировать, если исходят из базы данных, например,) имеет строку </script>, оператор замены позаботится о ней

https://github.com/pugjs/pug/blob/355d3dae/examples/dynamicscript.pug


#{} для экранированной интерполяции строк , которая подходит только при работе со строками. не работает с объектами

script var data = #{JSON.stringify(data)}

//=> <script>var data = {&quot;foo&quot;:&quot;bar&quot;}</script>
5 голосов
/ 12 мая 2018

В моем случае я пытался передать объект в шаблон через экспресс-маршрут (схожий с настройкой OP). Затем я хотел передать этот объект в функцию, которую вызывал через тег script в шаблоне pug. Хотя ответ lagginreflex приблизил меня, я получил следующее:

script.
    var data = JSON.parse('!{JSON.stringify(routeObj)}');
    funcName(data)

Это обеспечило передачу объекта, как и ожидалось, а не необходимость десериализации в функции. Кроме того, другие ответы, похоже, хорошо работали с примитивами, но когда массивы и т. Д. Передавались вместе с объектом, они анализировались как строковые значения.

4 голосов
/ 05 сентября 2018

Если вы похожи на меня и часто используете этот способ передачи переменных, вот решение для записи без кода.

В вашем файле node.js передайте переменные в объект с именем window, например:

router.get('/', function (req, res, next) {
    res.render('index', {
        window: {
            instance: instance
        }
    });
});

Затем в файле макета мопса / нефрита (непосредственно перед block content) вы получаете их следующим образом:

if window
    each object, key in window
        script.
            window.!{key} = !{JSON.stringify(object)};

Поскольку мой файл layout.pug загружается вместе с каждым файлом pug, мне не нужно «импортировать» мои переменные снова и снова.

Таким образом, все переменные / объекты, переданные window 'магическим образом', оказываются в реальном window объекте вашего браузера, где вы можете использовать их в Reactjs, Angular, ... или ванильном JavaScript.

2 голосов
/ 03 января 2012

См. Этот вопрос: JADE + EXPRESS: перебор объекта во встроенном коде JS (на стороне клиента)?

У меня та же проблема. Jade не передает локальные переменные (или вообще не использует шаблоны) в сценарии javascript, он просто передает весь блок как буквальный текст. Если вы используете локальные переменные 'address' и 'port' в вашем файле Jade над тегом script, они должны появиться.

Возможные решения перечислены в вопросе, на который я ссылался выше, но вы можете либо: - передать каждую строку как неэкранированный текст (! = в начале каждой строки) и просто поставить "-" перед каждой строкой JavaScript, которая использует локальную переменную, или: - Передайте переменные через элемент dom и получите доступ через JQuery (безобразно)

Нет лучшего способа? Кажется, создатели Jade не хотят поддержки многострочного JavaScript, как показано в этой теме в GitHub: https://github.com/visionmedia/jade/pull/405

1 голос
/ 19 октября 2016

Вот как я решил эту проблему (используя производную MEAN)

Мои переменные:

{
  NODE_ENV : development,
  ...
  ui_varables {
     var1: one,
     var2: two
  }
}

Сначала я должен был убедиться, что необходимые переменные конфигурации были переданы.MEAN использует пакет node nconf и по умолчанию настроен на ограничение того, какие переменные передаются из среды.Мне пришлось исправить это:

config / config.js:

оригинал:

nconf.argv()
  .env(['PORT', 'NODE_ENV', 'FORCE_DB_SYNC'] ) // Load only these environment variables
  .defaults({
  store: {
    NODE_ENV: 'development'
  }
});

после изменений:

nconf.argv()
  .env('__') // Load ALL environment variables
  // double-underscore replaces : as a way to denote hierarchy
  .defaults({
  store: {
    NODE_ENV: 'development'
  }
});

Теперь я могу установить свои переменные следующим образом:

export ui_varables__var1=first-value
export ui_varables__var2=second-value

Примечание: я сбросил «индикатор иерархии» на «__» (двойное подчеркивание), потому что его значение по умолчанию было «:», что делает переменные болеетрудно установить из Баш.Смотрите еще один пост в этой теме.

Теперь часть нефрита: Далее необходимо отобразить значения, чтобы javascript мог подобрать их на стороне клиента.Простой способ записать эти значения в индексный файл.Поскольку это одностраничное приложение (угловое), эта страница всегда загружается первой.Я думаю, что в идеале это должен быть включаемый файл javascript (просто, чтобы сохранить чистоту), но это хорошо для демонстрации.

app / controllers / index.js:

'use strict';
var config = require('../../config/config');

exports.render = function(req, res) {
  res.render('index', {
    user: req.user ? JSON.stringify(req.user) : "null",
    //new lines follow:
    config_defaults : {
       ui_defaults: JSON.stringify(config.configwriter_ui).replace(/<\//g, '<\\/')  //NOTE: the replace is xss prevention
    }
  });
};

app / views / index.jade:

extends layouts/default

block content
  section(ui-view)
    script(type="text/javascript").
    window.user = !{user};
    //new line here
    defaults = !{config_defaults.ui_defaults};

В моем рендеринге html это дает мне симпатичный маленький скрипт:

<script type="text/javascript">
 window.user = null;         
 defaults = {"var1":"first-value","var2:"second-value"};
</script>        

С этого момента легко использовать код.

...