Bagaimana cara melewatkan variabel dari file template giok ke file script?

119

Saya mengalami masalah dengan variabel (config) yang dideklarasikan dalam file template giok (index.jade) yang tidak diteruskan ke file javascript, yang kemudian membuat javascript saya macet. Ini file (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')

Berikut adalah bagian dari app.js saya (sisi server):

  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));

Dan berikut ini adalah bagian dari file javascript saya yang rusak (public / javascripts / app.js):

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

Saya menjalankan situs dalam mode pengembangan (NODE_ENV = pengembangan) di localhost (mesin saya sendiri). Saya menggunakan node-inspector untuk debugging, yang memberi tahu saya bahwa variabel config tidak ditentukan di public / javascripts / app.js.

Ada ide ?? Terima kasih!!

Michael Eilers Smith
sumber
kemungkinan duplikat variabel ExpressJS Pass ke JavaScript
laggingreflex

Jawaban:

174

Ini agak terlambat tapi ...

script.
  loginName="#{login}";

Ini berfungsi dengan baik di skrip saya. Di Express, saya melakukan ini:

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

Saya kira giok terbaru berbeda?

Merc.

edit: ditambahkan "." setelah skrip untuk mencegah peringatan Jade.

Merc
sumber
1
Terima kasih telah menerima jawabannya! Jadi, apa masalah sebenarnya dengan kode Anda?
Merc
Ya, saya mendapatkan ini bekerja juga dengan membungkus variabel lokal dalam template dalam tanda kutip dan indikator # {}.
Askdesigners
Jawaban ini berbahaya, jawaban lagginreflex dengan benar mengkodekan string (baris baru dalam nama login dapat memungkinkan eksekusi kode).
Paul Grove
Jadi masalahnya hanya tanda kutip tunggal sementara ganda diharapkan, bukan?
Augustin Riedinger
Bagi saya masalahnya adalah titiknya. Saya memilikinya di akhir blok skrip. Dengan titik setelah kata kunci "script" ini bekerja seperti pesona. Terima kasih!
Mirko
103

!{}adalah untuk interpolasi kode yang tidak lolos , yang lebih cocok untuk objek

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>

Idenya adalah untuk mencegah penyerang untuk:

  1. Keluar dari variabel: JSON.stringifykeluar dari tanda kutip
  2. Keluar dari tag skrip: jika konten variabel (yang mungkin tidak dapat Anda kendalikan jika berasal dari database misalnya) memiliki </script>string, pernyataan ganti akan menanganinya

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


#{}adalah untuk interpolasi string yang lolos , yang hanya cocok jika Anda bekerja dengan string. Itu tidak bekerja dengan objek

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

//=> <script>var data = {&quot;foo&quot;:&quot;bar&quot;}</script>
refleks tertinggal
sumber
1
Jawaban yang sangat bagus! Saya telah menelusuri subjek ini selama lebih dari 20 menit dan tidak ada jawaban lain yang menyatakan perbedaan antara! {} Dan # {}. Sepanjang waktu ini saya hanya berpikir! {] Tidak digunakan lagi setara dengan # {} ... Terima kasih lagi.
Patrick E.
Ke atas! Jawaban yang bagus.
Scarysize
Jawaban bagus, dan berfungsi untuk objek! Btw, apakah JSONobjek global? Sepertinya berfungsi tanpa mengimpor perpustakaan lain. Jika ya, bagaimana dengan dukungan browser?
chharvey
@chharvey JSON adalah bahasa javascript bawaan (seperti Tanggal atau Matematika), semua browser mendukungnya.
laggingreflex
1
Setuju ini adalah jawaban terbaik, tetapi menurut saya ini bukan tempat yang tepat untuk melepaskan diri dari string yang berpotensi berbahaya. IMO akan lebih baik untuk menghilangkan replacepanggilan dalam kode ini, dan memperlakukan nilai ini sama seperti input lainnya. JSON.stringify dijamin menghasilkan javascript yang valid (atau gagal), dan setelah Anda memiliki nilai yang berpotensi berbahaya ini di memori, Anda dapat memastikan untuk membersihkannya sesuai kebutuhan sebelum digunakan.
Riley Lark
9

Dalam kasus saya, saya mencoba untuk mengirimkan objek ke template melalui rute ekspres (mirip dengan pengaturan OP). Kemudian saya ingin meneruskan objek itu ke dalam fungsi yang saya panggil melalui tag skrip di template pug. Meskipun jawaban lagginreflex membuat saya dekat, saya berakhir dengan yang berikut:

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

Ini memastikan objek diteruskan seperti yang diharapkan, daripada perlu deserialisasi dalam fungsinya. Juga, jawaban lain tampaknya berfungsi dengan baik dengan primitif, tetapi ketika array dll diteruskan bersama dengan objek mereka diurai sebagai nilai string.

Kyle G
sumber
7

Jika Anda seperti saya dan Anda sering menggunakan metode penerusan variabel ini, berikut adalah solusi kode tanpa penulisan.

Di rute node.js Anda, teruskan variabel dalam objek yang disebut window, seperti ini:

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

Kemudian di file layout pug / jade Anda (tepat sebelum block content), Anda mengeluarkannya seperti ini:

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

Karena file layout.pug saya dimuat dengan setiap file pug, saya tidak perlu 'mengimpor' variabel saya berulang kali.

Dengan cara ini semua variabel / objek yang diteruskan ke window'secara ajaib' berakhir di windowobjek sebenarnya dari browser Anda di mana Anda dapat menggunakannya di Reactjs, Angular, ... atau vanilla javascript.

Sam
sumber
1
Ini adalah jawaban terbaik yang pernah saya lihat.
Tohir
3

Begini cara saya membahas ini (menggunakan turunan MEAN)

Variabel saya:

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

Pertama, saya harus memastikan bahwa variabel config yang diperlukan telah diteruskan. MEAN menggunakan paket node nconf, dan secara default diatur untuk membatasi variabel mana yang diteruskan dari lingkungan. Saya harus memperbaikinya:

config / config.js:

asli:

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

setelah modifikasi:

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

Sekarang saya dapat mengatur variabel saya seperti ini:

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

Catatan: Saya menyetel ulang "indikator heirarki" menjadi "__" (garis bawah ganda) karena defaultnya adalah ":", yang membuat variabel lebih sulit disetel dari bash. Lihat posting lain di utas ini.

Sekarang bagian giok: Selanjutnya nilai-nilai perlu dirender, sehingga javascript dapat mengambilnya di sisi klien. Cara mudah untuk menulis nilai ini ke file indeks. Karena ini adalah aplikasi satu halaman (bersudut), halaman ini selalu dimuat terlebih dahulu. Saya pikir idealnya ini harus berupa file penyertaan javascript (hanya untuk menjaga kebersihan), tetapi ini bagus untuk demo.

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};

Di html yang saya berikan, ini memberi saya skrip kecil yang bagus:

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

Dari titik ini, mudah bagi sudut untuk menggunakan kode tersebut.

Michael
sumber
Ini adalah cara bertele-tele yang sangat panjang untuk mengatakan apa yang sudah dikatakan oleh jawaban yang diterima. Selain itu, menyebutkan MEAN, nconf, dll tidak relevan. Pertanyaannya adalah tentang bagaimana meneruskan variabel ke klien, bukan tentang bagaimana Anda melakukan tumpukan dev Anda. Namun, jangan downvoting, karena Anda masih berusaha keras dalam jawaban ini.
Mrchief
terlalu rumit
andygoestohollywood
2

Lihat pertanyaan ini: JADE + EXPRESS: Iterasi objek dalam kode JS sebaris (sisi klien)?

Saya mempunyai masalah yang sama. Jade tidak meneruskan variabel lokal di (atau melakukan template sama sekali) ke skrip javascript, Jade hanya meneruskan seluruh blok sebagai teks literal. Jika Anda menggunakan 'alamat' variabel lokal dan 'port' di file Jade Anda di atas tag skrip, variabel tersebut akan muncul.

Solusi yang memungkinkan tercantum dalam pertanyaan yang saya tautkan di atas, tetapi Anda dapat: - meneruskan setiap baris sebagai teks yang tidak lolos (! = Di awal setiap baris), dan cukup letakkan "-" sebelum setiap baris javascript yang menggunakan variabel lokal, atau: - Meneruskan variabel melalui elemen dom dan mengakses melalui JQuery (jelek)

Apakah tidak ada cara yang lebih baik? Sepertinya pembuat Jade tidak menginginkan dukungan multiline javascript, seperti yang ditunjukkan oleh utas ini di GitHub: https://github.com/visionmedia/jade/pull/405

Varun Singh
sumber