New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Purescript bundle optimization issue. #2290
Comments
Is this running Browserify and then psc-bundle, or the other way round? |
Browserify is first I think, but I'm not sure. If I'm wrong about this being a psc-bundle issue that means there are some transforms defined somewhere that pulp passes to browserify I think, however I couldn't find them. EDIT: or a default browserify transformation could be eliminating this variable |
I would say it's wrong to apply Browserify then psc-bundle, so maybe it is a Pulp issue then. |
|
Also seeing this with "use strict"
var keyPrefix = "Jane.Cache.Event:"
var localStorageTested = false
var localStorage = window.localStorage
var unprocessedEventQueue = []
var readyEventQueue = []
var completedEventQueue = []
var push = Array.prototype.push
var batchUnprocessedCount = 10
var batchUnprocessedInterval = 100
var batchReadyCount = 1000
var batchReadyInterval = 5000
var batchCompletedCount = 10
var batchCompletedInterval = 100
var postEvents = null
exports._enqueueEvent = function (event) {
unprocessedEventQueue.push(event)
} And here's that file in the bundle: "use strict";
var unprocessedEventQueue = []
var push = Array.prototype.push.apply
var postEvents = null
exports._enqueueEvent = function (event) {
unprocessedEventQueue.push(event)
} It's consistent and only breaks on this file, which makes me think it has something to do with the contents of this file specifically.. |
@spicydonuts Can you post the whole file? It's hard to tell whether a variable is used without being able to see all potential usages. Also, the line
|
@michaelficarra On I don't think there are any unused variables (and normally the linter would warn if that were the case), but there most definitely are used variables getting removed. Here's the whole file: "use strict"
var keyPrefix = "Jane.Cache.Event:"
var localStorageTested = false
var localStorage = window.localStorage
var unprocessedEventQueue = []
var readyEventQueue = []
var completedEventQueue = []
var push = Array.prototype.push
var batchUnprocessedCount = 10
var batchUnprocessedInterval = 100
var batchReadyCount = 1000
var batchReadyInterval = 120000
var batchCompletedCount = 10
var batchCompletedInterval = 100
var postEvents = null
exports._enqueueEvent = function (event) {
unprocessedEventQueue.push(event)
}
function testLocalStorage () {
if (localStorageTested) return
localStorage.setItem("Jane.LocalStorageTest", "Success")
localStorageTested = true
}
function handleUnprocessed (numberToProcess) {
if (unprocessedEventQueue.length === 0) return
var toProcess = unprocessedEventQueue.splice(0, numberToProcess)
try {
testLocalStorage()
toProcess.forEach(function (event) {
localStorage.setItem(
keyPrefix + event.eventId,
JSON.stringify(event)
)
})
push.apply(readyEventQueue, toProcess)
} catch (err) {
console.warn("Failed to handle some unprocessed events", err)
push.apply(unprocessedEventQueue, toProcess)
}
}
function handleReady (numberToProcess) {
if (readyEventQueue.length === 0) return
var toProcess = readyEventQueue.splice(0, numberToProcess)
postEvents(toProcess)(success, failure)
function success () {
push.apply(completedEventQueue, toProcess)
}
function failure (err) {
console.warn("Failed to handle some ready events", err)
push.apply(readyEventQueue, toProcess)
}
}
function handleCompleted (numberToProcess) {
if (completedEventQueue.length === 0) return
var toProcess = completedEventQueue.splice(0, numberToProcess)
try {
testLocalStorage()
toProcess.forEach(function (event) {
localStorage.removeItem(keyPrefix + event.eventId)
})
} catch (err) {
console.warn("Failed to handle some completed events", err)
push.apply(completedEventQueue, toProcess)
}
}
function restoreReady () {
try {
testLocalStorage()
var keys = Object.keys(localStorage).filter(function (key) {
return key.startsWith(keyPrefix)
})
var toRestore = keys.map(function (key) {
return JSON.parse(localStorage.getItem(key))
})
push.apply(readyEventQueue, toRestore)
} catch (err) {
console.warn("Failed to restore ready events", err)
}
}
exports._initializeEventQueues = function (postEventsFn) {
postEvents = postEventsFn
restoreReady()
window.addEventListener("unload", function () {
handleUnprocessed(unprocessedEventQueue.length)
})
setInterval(function () {
handleUnprocessed(batchUnprocessedCount)
}, batchUnprocessedInterval)
setInterval(function () {
handleReady(batchReadyCount)
}, batchReadyInterval)
setInterval(function () {
handleCompleted(batchCompletedCount)
}, batchCompletedInterval)
} |
And here's that whole file in the bundle: "use strict";
var unprocessedEventQueue = []
var push = Array.prototype.push
var batchUnprocessedCount = 10
var batchUnprocessedInterval = 100
var batchReadyCount = 1000
var batchReadyInterval = 120000
var batchCompletedCount = 10
var batchCompletedInterval = 100
var postEvents = null
exports._enqueueEvent = function (event) {
unprocessedEventQueue.push(event)
}
function testLocalStorage () {
if (localStorageTested) return
localStorage.setItem("Jane.LocalStorageTest", "Success")
localStorageTested = true
}
function handleUnprocessed (numberToProcess) {
if (unprocessedEventQueue.length === 0) return
var toProcess = unprocessedEventQueue.splice(0, numberToProcess)
try {
testLocalStorage()
toProcess.forEach(function (event) {
localStorage.setItem(
keyPrefix + event.eventId,
JSON.stringify(event)
)
})
push.apply(readyEventQueue, toProcess)
} catch (err) {
console.warn("Failed to handle some unprocessed events", err)
push.apply(unprocessedEventQueue, toProcess)
}
}
function handleReady (numberToProcess) {
if (readyEventQueue.length === 0) return
var toProcess = readyEventQueue.splice(0, numberToProcess)
postEvents(toProcess)(success, failure)
function success () {
push.apply(completedEventQueue, toProcess)
}
function failure (err) {
console.warn("Failed to handle some ready events", err)
push.apply(readyEventQueue, toProcess)
}
}
function handleCompleted (numberToProcess) {
if (completedEventQueue.length === 0) return
var toProcess = completedEventQueue.splice(0, numberToProcess)
try {
testLocalStorage()
toProcess.forEach(function (event) {
localStorage.removeItem(keyPrefix + event.eventId)
})
} catch (err) {
console.warn("Failed to handle some completed events", err)
push.apply(completedEventQueue, toProcess)
}
}
function restoreReady () {
try {
testLocalStorage()
var keys = Object.keys(localStorage).filter(function (key) {
return key.startsWith(keyPrefix)
})
var toRestore = keys.map(function (key) {
return JSON.parse(localStorage.getItem(key))
})
push.apply(readyEventQueue, toRestore)
} catch (err) {
console.warn("Failed to restore ready events", err)
}
}
exports._initializeEventQueues = function (postEventsFn) {
postEvents = postEventsFn
restoreReady()
window.addEventListener("unload", function () {
handleUnprocessed(unprocessedEventQueue.length)
})
setInterval(function () {
handleUnprocessed(batchUnprocessedCount)
}, batchUnprocessedInterval)
setInterval(function () {
handleReady(batchReadyCount)
}, batchReadyInterval)
setInterval(function () {
handleCompleted(batchCompletedCount)
}, batchCompletedInterval)
} |
And sorry it took so long to reply; I missed your message somehow. |
I ended up getting it to work by setting my two exports to null at the top of the file, then moving the rest of the file into a self-calling function. |
So is this still considered a bug in |
I ended up rewriting this JS file last night but still saw the same issues (half of the vars removed). I also tried changing spaces for tabs and adding semicolons to every line. Same results, and the IIFE still fixes it. If it helps I can share the new version and its output. |
@spicydonuts Please do share the new version and it's output. |
Is it possible to reduce this down to a minimal test case please? |
Here is another way to reproduce this error:
This will result in a
|
The following observation might be helpful: function _compare(EQ, GT, LT, a, b) {
// Body
}
exports._compare = _compare; If that code is changed to exports._compare = function _compare (EQ, GT, LT, a, b) {
// Body
};
|
Yes, it's important that foreign modules are structured in the right way so that |
Ah, so we need to fix this in argonaut: https://github.com/purescript-contrib/purescript-argonaut-core/blob/576563b5fbf989d725b6f3128465c1ca45ecc0aa/src/Data/Argonaut/Core.js I actually don't remember if we documented the requirements for Also, is it feasible to detect errors like this one at compile-time? |
This does indeed look like the kind of psc-bundle bug you thought it was, and I have a minimal reproducing case here: https://github.com/hdgarrood/psc-bundle-repro psc-bundle seems to be leaving function declarations alone but removing statements like |
I suppose this hasn't been affecting others much or there would be more comments or duplicate issues. However, I feel like this is a pretty serious issue and should be resolved. I'll test later to see if it is still present with the latest version of Purescript. |
@codygman It affected me too, but I simply used a workaround (and nowadays I use I agree it should definitely be fixed if it's still present. |
If I'm understanding everything correctly, some transform that psc-bundle does eliminates a needed variable declaration. Minimum reproduction and some notes at the repo below:
https://github.com/codygman/purescript-optimize-issue
I also created an issue in purescript-contrib/pulp#227 since turning on optimization with pulp browserify ends up being affected by this runtime error bug due to a necessary var declaration being optimized away.
The text was updated successfully, but these errors were encountered: