Peruse Mock returning blank page - Sorry, peruse does not support window.eval()


#1

Site: https://gitlab.com/UniversalBasics/Yropeen/Site-Yropeen
OS: Arch Linux
Browser: Peruse webId-Builds
env: mock

The whole site is white and there’s only a window.eval() error showing up.


#2

window.eval() is not available in Peruse for security reasons. I’d wager it’s this error that’s causing your site to crash.


#3

How about injecting something that will print an explanatory error for this and other unsupported features?


#4

:+1:

We could add on ‘for security reasons’, i suppose. But that error should be clear enough.


#5

Where does my site, or safe_web_app_quick_start of the tutorial for that matter, call window.eval() in the first place?


#6

I haven’t checked your code, so I’m not sure. Is the above error the error that you see?

Have you checked to see if eval is being called at all in your code?

If you’re not using window.eval then that is indeed strange. Maybe you can provide more info on the error and your system. Is the site published on the network or are you running localhost?


#7

I think it is being called in one of the packages I use.
I’ll dig deeper into it when I get home.

localhost

[edit]

This does not seem to be related to my own code.
Even the safe web example has this.

It seems to be related to webpack.

Uncaught Error: Sorry, peruse does not support window.eval().
    at window.eval.global.eval (/opt/Maidsafe/Peruse/resources/app.asar/webPreload.js:9:83345)
    at Object../node_modules/webpack-dev-server/client/index.js?http://localhost:5000 (http://localhost:5000/index.js:962:1)
    at __webpack_require__ (http://localhost:5000/index.js:679:30)
    at fn (http://localhost:5000/index.js:89:20)
    at Object.0 (http://localhost:5000/index.js:1057:1)
    at __webpack_require__ (http://localhost:5000/index.js:679:30)
    at http://localhost:5000/index.js:725:37
    at http://localhost:5000/index.js:728:100:

…/node_modules/webpack-dev-server/client/index.js

"use strict";
eval("/* WEBPACK VAR INJECTION */(function(__resourceQuery) {\n\n/* global __resourceQuery 
WorkerGlobalScope self */\n/* eslint prefer-destructuring: off */\n\nvar url = 
__webpack_require__(\"./node_modules/url/url.js\");\nvar stripAnsi = 
__webpack_require__(\"./node_modules/strip-ansi/index.js\");\nvar log = 
__webpack_require__(\"./node_modules/loglevel/lib/loglevel.js\").getLogger('webpack-dev-server');\nvar 
socket = __webpack_require__(\"./node_modules/webpack-dev-server/client/socket.js\");\nvar overlay = 
__webpack_require__(\"./node_modules/webpack-dev-server/client/overlay.js\");\n\nfunction 
getCurrentScriptSource() {\n  // `document.currentScript` is the most accurate way to find the current 
script,\n  // but is not supported in all browsers.\n  if (document.currentScript) {\n    return 
document.currentScript.getAttribute('src');\n  }\n  // Fall back to getting all scripts in the document.\n  var 
scriptElements = document.scripts || [];\n  var currentScript = scriptElements[scriptElements.length - 1];\n  if 
(currentScript) {\n    return currentScript.getAttribute('src');\n  }\n  // Fail as there was no script to use.\n  
throw new Error('[WDS] Failed to get current script source.');\n}\n\nvar urlParts = void 0;\nvar hotReload = 
true;\nif (typeof window !== 'undefined') {\n  var qs = window.location.search.toLowerCase();\n  hotReload = 
qs.indexOf('hotreload=false') === -1;\n}\nif (true) {\n  // If this bundle is inlined, use the resource query to get 
the correct url.\n  urlParts = url.parse(__resourceQuery.substr(1));\n} else {\n  // Else, get the url from the 
<script> this file was called with.\n  var scriptHost = getCurrentScriptSource();\n  // eslint-disable-next-line no-
useless-escape\n  scriptHost = scriptHost.replace(/\\/[^\\/]+$/, '');\n  urlParts = url.parse(scriptHost || '/', false, 
true);\n}\n\nif (!urlParts.port || urlParts.port === '0') {\n  urlParts.port = self.location.port;\n}\n\nvar _hot = 
false;\nvar initial = true;\nvar currentHash = '';\nvar useWarningOverlay = false;\nvar useErrorOverlay = 
false;\nvar useProgress = false;\n\nvar INFO = 'info';\nvar WARNING = 'warning';\nvar ERROR = 'error';\nvar 
NONE = 'none';\n\n// Set the default log level\nlog.setDefaultLevel(INFO);\n\n// Send messages to the 
outside, so plugins can consume it.\nfunction sendMsg(type, data) {\n  if (typeof self !== 'undefined' && 
(typeof WorkerGlobalScope === 'undefined' || !(self instanceof WorkerGlobalScope))) {\n    
self.postMessage({\n      type: 'webpack' + type,\n      data: data\n    }, '*');\n  }\n}\n\nvar onSocketMsg = {\n  
hot: function hot() {\n    _hot = true;\n    log.info('[WDS] Hot Module Replacement enabled.');\n  },\n  invalid: 
function invalid() {\n    log.info('[WDS] App updated. Recompiling...');\n    // fixes #1042. overlay doesn't clear 
if errors are fixed but warnings remain.\n    if (useWarningOverlay || useErrorOverlay) overlay.clear();\n    
sendMsg('Invalid');\n  },\n  hash: function hash(_hash) {\n    currentHash = _hash;\n  },\n\n  'still-ok': function 
stillOk() {\n    log.info('[WDS] Nothing changed.');\n    if (useWarningOverlay || useErrorOverlay) 
overlay.clear();\n    sendMsg('StillOk');\n  },\n  'log-level': function logLevel(level) {\n    var hotCtx = 
__webpack_require__(\"./node_modules/webpack/hot ^\\\\.\\\\/log$\");\n    if (hotCtx.keys().indexOf('./log') !== 
-1) {\n      hotCtx('./log').setLogLevel(level);\n    }\n    switch (level) {\n      case INFO:\n      case ERROR:\n        
log.setLevel(level);\n        break;\n      case WARNING:\n        // loglevel's warning name is different from 
webpack's\n        log.setLevel('warn');\n        break;\n      case NONE:\n        log.disableAll();\n        break;\n      
default:\n        log.error('[WDS] Unknown clientLogLevel \\'' + level + '\\'');\n    }\n  },\n  overlay: function 
overlay(value) {\n    if (typeof document !== 'undefined') {\n      if (typeof value === 'boolean') {\n        
useWarningOverlay = false;\n        useErrorOverlay = value;\n      } else if (value) {\n        useWarningOverlay 
= value.warnings;\n        useErrorOverlay = value.errors;\n      }\n    }\n  },\n  progress: function 
progress(_progress) {\n    if (typeof document !== 'undefined') {\n      useProgress = _progress;\n    }\n  },\n\n  
'progress-update': function progressUpdate(data) {\n    if (useProgress) log.info('[WDS] ' + data.percent + '% 
- ' + data.msg + '.');\n  },\n  ok: function ok() {\n    sendMsg('Ok');\n    if (useWarningOverlay || 
useErrorOverlay) overlay.clear();\n    if (initial) return initial = false; // eslint-disable-line no-return-assign\n    
reloadApp();\n  },\n\n  'content-changed': function contentChanged() {\n    log.info('[WDS] Content base 
changed. Reloading...');\n    self.location.reload();\n  },\n  warnings: function warnings(_warnings) {\n    
log.warn('[WDS] Warnings while compiling.');\n    var strippedWarnings = _warnings.map(function (warning) 
{\n      return stripAnsi(warning);\n    });\n    sendMsg('Warnings', strippedWarnings);\n    for (var i = 0; i < 
strippedWarnings.length; i++) {\n      log.warn(strippedWarnings[i]);\n    }\n    if (useWarningOverlay) 
overlay.showMessage(_warnings);\n\n    if (initial) return initial = false; // eslint-disable-line no-return-assign\n    
reloadApp();\n  },\n  errors: function errors(_errors) {\n    log.error('[WDS] Errors while compiling. Reload 
prevented.');\n    var strippedErrors = _errors.map(function (error) {\n      return stripAnsi(error);\n    });\n    
sendMsg('Errors', strippedErrors);\n    for (var i = 0; i < strippedErrors.length; i++) {\n      
log.error(strippedErrors[i]);\n    }\n    if (useErrorOverlay) overlay.showMessage(_errors);\n    initial = false;\n  
},\n  error: function error(_error) {\n    log.error(_error);\n  },\n  close: function close() {\n    log.error('[WDS] 
Disconnected!');\n    sendMsg('Close');\n  }\n};\n\nvar hostname = urlParts.hostname;\nvar protocol = 
urlParts.protocol;\n\n// check ipv4 and ipv6 `all hostname`\nif (hostname === '0.0.0.0' || hostname === '::') {\n  
// why do we need this check?\n  // hostname n/a for file protocol (example, when using electron, ionic)\n  // 
see: https://github.com/webpack/webpack-dev-server/pull/384\n  // eslint-disable-next-line no-bitwise\n  if 
(self.location.hostname && !!~self.location.protocol.indexOf('http')) {\n    hostname = 
self.location.hostname;\n  }\n}\n\n// `hostname` can be empty when the script path is relative. In that case, 
specifying\n// a protocol would result in an invalid URL.\n// When https is used in the app, secure websockets 
are always necessary\n// because the browser doesn't accept non-secure websockets.\nif (hostname && 
(self.location.protocol === 'https:' || urlParts.hostname === '0.0.0.0')) {\n  protocol = self.location.protocol;\n}
\n\nvar socketUrl = url.format({\n  protocol: protocol,\n  auth: urlParts.auth,\n  hostname: hostname,\n  port: 
urlParts.port,\n  pathname: urlParts.path == null || urlParts.path === '/' ? '/sockjs-node' : urlParts.path\n});
\n\nsocket(socketUrl, onSocketMsg);\n\nvar isUnloading = false;\nself.addEventListener('beforeunload', 
function () {\n  isUnloading = true;\n});\n\nfunction reloadApp() {\n  if (isUnloading || !hotReload) {\n    
return;\n  }\n  if (_hot) {\n    log.info('[WDS] App hot update...');\n    // eslint-disable-next-line global-require\n    
var hotEmitter = __webpack_require__(\"./node_modules/webpack/hot/emitter.js\");\n    
hotEmitter.emit('webpackHotUpdate', currentHash);\n    if (typeof self !== 'undefined' && self.window) {\n      // 
broadcast update to window\n      self.postMessage('webpackHotUpdate' + currentHash, '*');\n    }\n  } else 
{\n    var rootWindow = self;\n    // use parent window for reload (in case we're in an iframe with no valid 
src)\n    var intervalId = self.setInterval(function () {\n      if (rootWindow.location.protocol !== 'about:') {\n        
// reload immediately if protocol is valid\n        applyReload(rootWindow, intervalId);\n      } else {\n        
rootWindow = rootWindow.parent;\n        if (rootWindow.parent === rootWindow) {\n          // if parent equals 
current window we've reached the root which would continue forever, so trigger a reload anyways\n          
applyReload(rootWindow, intervalId);\n        }\n      }\n    });\n  }\n\n  function applyReload(rootWindow, 
intervalId) {\n    clearInterval(intervalId);\n    log.info('[WDS] App updated. Reloading...');\n    
rootWindow.location.reload();\n  }\n}\n/* WEBPACK VAR INJECTION */}.call(exports, \"?http://localhost:5000
\"))//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-
8;base64,eyJ2Z...n0IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/webpack-dev-server/client
/index.js?http://localhost:5000\n");

#8

Can you try with this version of the browser please:

I think the eval override came in with the webId POC stuff (I think). So that version may go for you. If that is the case, we’ll need to update the example.

It seems like the key thing would be turning off hot_reloading in webpack, as that’s attempting to trigger the eval statement.


#9

But how to turn off hot reloading?

I’ve tried this without success:

webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          hotReload: false 
        }
      }
    ]
  }
}

neutrinorc.js

module.exports = {
  use: [
    [
      '@neutrinojs/vue',
      {
        html: {
          title: 'SAFE Web App'
        }
      }
    ],
    (neutrino) => {
      neutrino.config.module
        .rule('vue')
          .test(/\.vue$/)
        .use('vue')
          .loader('vue-loader')
          .options({hotReload: false});
    }
  ]
};

#10

You’ll probably need to consult the vue loader docs to find that out.


#11

Wrong package. I think I need to disable webpack-dev-server instead.

Yet this doesn’t work either:

webpack.config.js

module.exports = {
  devServer: {
    hot: false,
    inline: false
  }
};

neutrinorc.js

module.exports = {
  use: [
    [
      '@neutrinojs/vue',
      {
        html: {
          title: 'SAFE Web App'
        }
      }
    ],
    (neutrino) => {
      neutrino.config.devServer
        .hot(false)
        .inline(false)
    }
  ]
};

[update]

Nor this

neutrinorc.js

module.exports = {
  use: [
    [
      '@neutrinojs/vue',
      {
        hot: false,
        html: {
          title: 'SAFE Web App'
        },
        devServer: {
          hot: false,
          hotOnly: false
       }
      }
    ]
  ]
};

#12

I’ve gotten into the same issue using Vue. I think it’s impossible to use the runtime version of Vue without the use of eval. eval is used by Vue to compile the templates.

To test the Vue application you’d have to build it, then serve it (or does Peruse allow file:// browsing?).

@joshuef, is there any chance of the eval coming back? It seems it is relied on by a few progressive web frameworks at least.


edit: I assumed @Folatt was using the latest vue-cli 3, but it seems you’ve been using version 2. I just successfully tested a Vue 2 application with hot reloading in Peruse using this template: https://github.com/vuejs-templates/browserify

Btw, @Folatt, I see you’re using Babel in your code — I think that’s unnecessary as your only targeted browser is Peruse, which is supporting the latest and greatest JS etc. Using the templates for vue-cli I think you should try and minimize the additional plugins you use.


#13

As far as I can tell, I’m not using vue-cli.
I’m not familiar with the many npmjs packages out there.
It’s all new to me.
I’ve tried minimizing the amount of plugins I use, but these were the ones I was “left” with:

Btw, @Folatt, I see you’re using Babel in your code — I think that’s unnecessary as your only targeted browser is Peruse, which is supporting the latest and greatest JS etc.

What babel code should I scrap?
All I know is that I like importing files from root, so I added babel-plugin-root-import.


#14

I saw the babel-preset-stage-2 dependency which is outdated and the .babelrc files — I didn’t know you only used Babel for importing files.

Ah! Then you did a fine job in creating that project yourself, as setting up such a project in combination with Webpack and hot reloading etc! I always found it a little tiresome and confusing — which is why Vue made a tool to scaffold a project for you.

Give https://github.com/vuejs-templates/browserify a try to have it scaffold a project for you.


#15

Despite being new with all of this, I do know that neutrino is supposed to make using webpack a lot easier.
Except for the hot reloading issue.


#16

That version also contains the eval override:


@joshuef, would it be sensible to allow eval for development (either when using mock or NODE_ENV on dev)?

Something like this (can’t figure out the right way to do it quickly (https://stackoverflow.com/a/2567051/2703418) but I guess you get the gist):

window.eval = global.eval = () =>
{
    if (process.env.NODE_ENV === 'production') {
        throw new Error( 'Sorry, peruse does not support window.eval().' );
    }
    
    return window.eval.apply(this, arguments);
};

#17

Solved by the neutrino dev team :slight_smile:

module.exports = {
  use: [
    ['@neutrinojs/vue', {
      // Existing options
    }],
    (neutrino) => {
      if (process.env.NODE_ENV === 'development') {
        // Override the default development source map of 'cheap-module-eval-source-map'
        // to one that doesn't use `eval` (reduces incremental build performance).
        neutrino.config.devtool('cheap-module-source-map');
      }
    }
  ]
};

#18

Cool! Good to see it could be solved. Might see if this is something that I can use as a solution too without NeutrinoJS.

Linking the solution for future reference btw: https://github.com/neutrinojs/neutrino/issues/1063#issuecomment-417618637


edit: Yaay, the same solution can be applied to the project generated by vue-cli:

// vue.config.js

module.exports = {
  chainWebpack: config => {
    config.devtool('cheap-module-source-map');
  },
}

Really awesome that the guy from NeutrinJS got it figured out.

I’m even more confused than before about source maps. Didn’t know the client passively inspects and executes the source maps on the background — thought it was only for inspection and debugging using the devtools.