jadeテンプレートファイルからスクリプトファイルに変数を渡す方法は?


119

javascriptファイルに渡されないjadeテンプレートファイル(index.jade)で宣言された変数(config)で問題が発生し、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 = development)でサイトを実行しています。node-inspectorをデバッグに使用しています。これにより、config変数がpublic / javascripts / app.jsで未定義であることがわかりました。

何か案は??ありがとう!!


回答:


174

それはだ少し遅れてますが...

script.
  loginName="#{login}";

これは私のスクリプトでは問題なく機能しています。Expressでは、私はこれをやっています:

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

最新のヒスイは違うのかな?

Merc。

編集:「。」を追加 ジェイド警告を防ぐためのスクリプトの後。


1
答えを受け入れてくれてありがとう!それで、あなたのコードの実際の問題は何でしたか?
Mercは

はい、テンプレート内のローカル変数を引用符で囲み、#{}インジケーターを付けることでも、これは機能します。
Askdesigners、2015

この答えは危険です。lagginreflexの答えは文字列を正しくエンコードします(ログイン名の改行でコードが実行される可能性があります)。
ポールグローブ

したがって、問題は一重引用符だけでしたが、二重が期待されていますよね?
オーガスティンリーディンガー2017年

私にとって問題はドットでした。スクリプトブロックの最後にありました。「script」キーワードの後のドットは、魅力のように機能します。ありがとうございました!
Mirko

102

!{}するためのものであるエスケープコードに適して補間、オブジェクト

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>文字列がある場合、replaceステートメントがそれを処理します

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>

1
正解です。私はこのテーマを20分以上検索してきましたが、他に!{}と#{}の違いについての回答はありませんでした。この間ずっと、!{]は非推奨の#{}に相当するものだと思っていました...ありがとうございます。
Patrick E.

頂点に!すばらしい答えです。
2016年

すばらしい答えであり、オブジェクトに対して機能します!ところで、JSONグローバルオブジェクトですか?他のライブラリをインポートしなくても機能するようです。もしそうなら、ブラウザのサポートはどうですか?
chharvey

@chharvey JSONは組み込みのJavaScript言語(DateやMathなど)であり、すべてのブラウザーでサポートされています。
laggingreflex 2016

1
これが最良の答えであることに同意しますが、これは潜在的に危険な文字列をエスケープするのに適切な場所だとは思いません。IMO replaceこのコードで呼び出しを省略し、この値を他の入力と同じように処理することをお勧めします。JSON.stringifyは有効なJavaScriptを生成する(または失敗する)ことが保証されており、この潜在的に危険な値をメモリに格納したら、使用前に必要に応じて確実にサニタイズできます。
Riley Lark

9

私の場合、エクスプレスルートを介してオブジェクトをテンプレートに渡そうとしました(OP設定と同様)。次に、そのオブジェクトを、pugテンプレートのスクリプトタグを介して呼び出す関数に渡したかったのです。けれどもlagginreflexの答えは近い私を得た、私は次のようになってしまいました。

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

これにより、関数でデシリアライズする必要がなく、オブジェクトが期待どおりに渡されることが保証されました。また、他の回答はプリミティブでうまく機能するように見えましたが、配列などがオブジェクトとともに渡された場合、それらは文字列値として解析されました。


7

私と同じように、変数を渡すこの方法を頻繁に使用する場合は、以下に書き込みのないコードソリューションを示します。

node.jsルートでwindow、次のようにと呼ばれるオブジェクトに変数を渡します。

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

次に、pug / jadeレイアウトファイル(の直前block content)で、次のようにそれらを取得します。

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

layout.pugファイルが各pugファイルと共にロードされるので、変数を何度も「インポート」する必要はありません。

このようにして、window「魔法のように」渡されたすべての変数/ windowオブジェクトは、ブラウザの実際のオブジェクトになり、Reactjs、AngularなどのバニラJavaScriptで使用できます。


1
これは私が見た中で最良の答えです。
Tohir、

3

これは私がこれに対処する方法です(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

注:デフォルトは ":"だったため、 "階層インジケーター"を "__"(二重下線)にリセットしました。これにより、bashから変数を設定するのが難しくなります。このスレッドの別の投稿を参照してください。

次にヒスイの部分:次に、JavaScriptがクライアント側で値を取得できるように、値をレンダリングする必要があります。これらの値をインデックスファイルに書き込む簡単な方法。これは1ページのアプリ(angular)であるため、このページが常に最初に読み込まれます。理想的には、これは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>        

この時点から、angularがコードを利用するのは簡単です。


これは、受け入れられた答えがすでに言っていることを言う非常に長い風の方法です。さらに、MEANやnconfなどについて言及しても問題はありません。問題は、変数をクライアントに渡す方法についてであり、開発スタックをどのように実行したかではありません。ただし、この回答にはまだ多大な労力を費やしているため、反対票を投じないでください。
Mrchief、

過度に複雑
andygoestohollywood

2

この質問を参照してください:JADE + EXPRESS:インラインJSコード(クライアント側)でオブジェクトを反復処理しますか?

私も同じ問題を抱えています。JadeはJavaScriptのスクリプトにローカル変数を渡さない(またはテンプレート化をまったく行わない)、ブロック全体をリテラルテキストとして渡すだけです。Jadeファイルでスクリプトタグの上のローカル変数「address」と「port」を使用すると、それらが表示されます。

考えられる解決策は上記の質問に記載されていますが、次のいずれかを行うことができます。ローカル変数、または:-DOM要素を介して変数を渡し、JQueryを介してアクセスします(醜い)

より良い方法はありませんか?GadeHubの次のスレッドで示されているように、Jadeの作成者は複数行のJavaScriptサポートを望んでいないようです:https : //github.com/visionmedia/jade/pull/405

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.