| Serialize JavaScript |
| ==================== |
| |
| Serialize JavaScript to a _superset_ of JSON that includes regular expressions, dates and functions. |
| |
| [![npm Version][npm-badge]][npm] |
|  |
| |
| ## Overview |
| |
| The code in this package began its life as an internal module to [express-state][]. To expand its usefulness, it now lives as `serialize-javascript` — an independent package on npm. |
| |
| You're probably wondering: **What about `JSON.stringify()`!?** We've found that sometimes we need to serialize JavaScript **functions**, **regexps**, **dates**, **sets** or **maps**. A great example is a web app that uses client-side URL routing where the route definitions are regexps that need to be shared from the server to the client. |
| |
| The string returned from this package's single export function is literal JavaScript which can be saved to a `.js` file, or be embedded into an HTML document by making the content of a `<script>` element. |
| |
| > **HTML characters and JavaScript line terminators are escaped automatically.** |
| |
| Please note that serialization for ES6 Sets & Maps requires support for `Array.from` (not available in IE or Node < 0.12), or an `Array.from` polyfill. |
| |
| > [!WARNING] |
| > It may be tempting to use this package as a way to pass arbitrary functions into [worker threads][], since you cannot pass them directly via `postMessage()`. However, passing functions between worker threads is not possible in the general case. This package lets you serialize *some* functions, but it has limitations. |
| > |
| > For instance, if a function references something from outside the function body, it will not run properly if serialized and deserialized. This could include [closed-over variables][] or imports from other packages. For a serialized function to run properly, it must be entirely self-contained. |
| > |
| > In general, it is not possible to send arbitrary JavaScript to a worker thread, and pretend it's running the same way it would run on the main thread. This package doesn't let you do that. |
| |
| ## Installation |
| |
| Install using npm: |
| |
| ```shell |
| $ npm install serialize-javascript |
| ``` |
| |
| ## Usage |
| |
| ```js |
| var serialize = require('serialize-javascript'); |
| |
| serialize({ |
| str : 'string', |
| num : 0, |
| obj : {foo: 'foo'}, |
| arr : [1, 2, 3], |
| bool : true, |
| nil : null, |
| undef: undefined, |
| inf : Infinity, |
| date : new Date("Thu, 28 Apr 2016 22:02:17 GMT"), |
| map : new Map([['hello', 'world']]), |
| set : new Set([123, 456]), |
| fn : function echo(arg) { return arg; }, |
| re : /([^\s]+)/g, |
| big : BigInt(10), |
| url : new URL('https://example.com/'), |
| }); |
| ``` |
| |
| The above will produce the following string output: |
| |
| ```js |
| '{"str":"string","num":0,"obj":{"foo":"foo"},"arr":[1,2,3],"bool":true,"nil":null,"undef":undefined,"inf":Infinity,"date":new Date("2016-04-28T22:02:17.000Z"),"map":new Map([["hello","world"]]),"set":new Set([123,456]),"fn":function echo(arg) { return arg; },"re":new RegExp("([^\\\\s]+)", "g"),"big":BigInt("10"),"url":new URL("https://example.com/")}' |
| ``` |
| |
| Note: to produce a beautified string, you can pass an optional second argument to `serialize()` to define the number of spaces to be used for the indentation. |
| |
| ### Automatic Escaping of HTML Characters |
| |
| A primary feature of this package is to serialize code to a string of literal JavaScript which can be embedded in an HTML document by adding it as the contents of the `<script>` element. In order to make this safe, HTML characters and JavaScript line terminators are escaped automatically. |
| |
| ```js |
| serialize({ |
| haxorXSS: '</script>' |
| }); |
| ``` |
| |
| The above will produce the following string, HTML-escaped output which is safe to put into an HTML document as it will not cause the inline script element to terminate: |
| |
| ```js |
| '{"haxorXSS":"\\u003C\\u002Fscript\\u003E"}' |
| ``` |
| |
| > You can pass an optional `unsafe` argument to `serialize()` for straight serialization. |
| |
| ### Options |
| |
| The `serialize()` function accepts an `options` object as its second argument. All options are being defaulted to `undefined`: |
| |
| #### `options.space` |
| |
| This option is the same as the `space` argument that can be passed to [`JSON.stringify`][JSON.stringify]. It can be used to add whitespace and indentation to the serialized output to make it more readable. |
| |
| ```js |
| serialize(obj, {space: 2}); |
| ``` |
| |
| #### `options.isJSON` |
| |
| This option is a signal to `serialize()` that the object being serialized does not contain any function or regexps values. This enables a hot-path that allows serialization to be over 3x faster. If you're serializing a lot of data, and know its pure JSON, then you can enable this option for a speed-up. |
| |
| **Note:** That when using this option, the output will still be escaped to protect against XSS. |
| |
| ```js |
| serialize(obj, {isJSON: true}); |
| ``` |
| |
| #### `options.unsafe` |
| |
| This option is to signal `serialize()` that we want to do a straight conversion, without the XSS protection. This options needs to be explicitly set to `true`. HTML characters and JavaScript line terminators will not be escaped. You will have to roll your own. |
| |
| ```js |
| serialize(obj, {unsafe: true}); |
| ``` |
| |
| #### `options.ignoreFunction` |
| |
| This option is to signal `serialize()` that we do not want serialize JavaScript function. |
| Just treat function like `JSON.stringify` do, but other features will work as expected. |
| |
| ```js |
| serialize(obj, {ignoreFunction: true}); |
| ``` |
| |
| ## Deserializing |
| |
| For some use cases you might also need to deserialize the string. This is explicitly not part of this module. However, you can easily write it yourself: |
| |
| ```js |
| function deserialize(serializedJavascript){ |
| return eval('(' + serializedJavascript + ')'); |
| } |
| ``` |
| |
| **Note:** Don't forget the parentheses around the serialized javascript, as the opening bracket `{` will be considered to be the start of a body. |
| |
| ## License |
| |
| This software is free to use under the Yahoo! Inc. BSD license. |
| See the [LICENSE file][LICENSE] for license text and copyright information. |
| |
| |
| [npm]: https://www.npmjs.org/package/serialize-javascript |
| [npm-badge]: https://img.shields.io/npm/v/serialize-javascript.svg?style=flat-square |
| [express-state]: https://github.com/yahoo/express-state |
| [JSON.stringify]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify |
| [LICENSE]: https://github.com/yahoo/serialize-javascript/blob/main/LICENSE |
| [worker threads]: https://nodejs.org/api/worker_threads.html |
| [closed-over variables]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures |