isaacs / sax-js

A sax style parser for JS
Other
1.09k stars 325 forks source link

browser support #121

Open weepy opened 10 years ago

weepy commented 10 years ago

How hard would it be to run this in the browser ?

I notice there's a requirement on "stream" - which AFAIK isn't available to the browser.

philmander commented 10 years ago

I'm running it in the browser sucessfully using Browserify, which automatically adds shims for certain core Node modules

Antony74 commented 9 years ago

Runs fine in-browser for me http://akb.me.uk/xml-checker/

DavidPeicho commented 6 years ago

It runs effectively well in Nodejs or with Browserify. Otherwise, with webpack, it is really painful to make it work.

SethFalco commented 4 months ago

In SVGO, we achieved this by just applying a patch to remove all the stream related code before generating the browser bundle.

You can use either the built-in functionality in Yarn or pnpm, or use patch-package on npm to write or generate a patch file in your repository.

Ours is written for sax v1.4.1, and looks like this:

diff --git a/lib/sax.js b/lib/sax.js
index 122ad8e5a478339d56fc86d00d21c5d142739f0e..2557c46482ff651026436cc6c7142ebfe68ddfc5 100644
--- a/lib/sax.js
+++ b/lib/sax.js
@@ -1,8 +1,6 @@
 ;(function (sax) { // wrapper for non-node envs
   sax.parser = function (strict, opt) { return new SAXParser(strict, opt) }
   sax.SAXParser = SAXParser
-  sax.SAXStream = SAXStream
-  sax.createStream = createStream

   // When we pass the MAX_BUFFER_LENGTH position, start checking for buffer overruns.
   // When we check, schedule the next check for MAX_BUFFER_LENGTH - (max(buffer lengths)),
@@ -164,111 +162,6 @@
     flush: function () { flushBuffers(this) }
   }

-  var Stream
-  try {
-    Stream = require('stream').Stream
-  } catch (ex) {
-    Stream = function () {}
-  }
-  if (!Stream) Stream = function () {}
-
-  var streamWraps = sax.EVENTS.filter(function (ev) {
-    return ev !== 'error' && ev !== 'end'
-  })
-
-  function createStream (strict, opt) {
-    return new SAXStream(strict, opt)
-  }
-
-  function SAXStream (strict, opt) {
-    if (!(this instanceof SAXStream)) {
-      return new SAXStream(strict, opt)
-    }
-
-    Stream.apply(this)
-
-    this._parser = new SAXParser(strict, opt)
-    this.writable = true
-    this.readable = true
-
-    var me = this
-
-    this._parser.onend = function () {
-      me.emit('end')
-    }
-
-    this._parser.onerror = function (er) {
-      me.emit('error', er)
-
-      // if didn't throw, then means error was handled.
-      // go ahead and clear error, so we can write again.
-      me._parser.error = null
-    }
-
-    this._decoder = null
-
-    streamWraps.forEach(function (ev) {
-      Object.defineProperty(me, 'on' + ev, {
-        get: function () {
-          return me._parser['on' + ev]
-        },
-        set: function (h) {
-          if (!h) {
-            me.removeAllListeners(ev)
-            me._parser['on' + ev] = h
-            return h
-          }
-          me.on(ev, h)
-        },
-        enumerable: true,
-        configurable: false
-      })
-    })
-  }
-
-  SAXStream.prototype = Object.create(Stream.prototype, {
-    constructor: {
-      value: SAXStream
-    }
-  })
-
-  SAXStream.prototype.write = function (data) {
-    if (typeof Buffer === 'function' &&
-      typeof Buffer.isBuffer === 'function' &&
-      Buffer.isBuffer(data)) {
-      if (!this._decoder) {
-        var SD = require('string_decoder').StringDecoder
-        this._decoder = new SD('utf8')
-      }
-      data = this._decoder.write(data)
-    }
-
-    this._parser.write(data.toString())
-    this.emit('data', data)
-    return true
-  }
-
-  SAXStream.prototype.end = function (chunk) {
-    if (chunk && chunk.length) {
-      this.write(chunk)
-    }
-    this._parser.end()
-    return true
-  }
-
-  SAXStream.prototype.on = function (ev, handler) {
-    var me = this
-    if (!me._parser['on' + ev] && streamWraps.indexOf(ev) !== -1) {
-      me._parser['on' + ev] = function () {
-        var args = arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments)
-        args.splice(0, 0, ev)
-        me.emit.apply(me, args)
-      }
-    }
-
-    return Stream.prototype.on.call(me, ev, handler)
-  }
-
   // this really needs to be replaced with character classes.
   // XML allows all manner of ridiculous numbers and digits.
   var CDATA = '[CDATA['

In our case, Yarn automatically applies patches that are found in the .yarn/patches directory. It's perfectly acceptable for cases where you are generating build artifacts or bundles.

It's lighter than maintaining a fork, and may be a viable temporary solution until something can be worked out upstream.