Skip to content
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

issues with vitejs #1744

Closed
flx-sta opened this issue Apr 29, 2021 · 18 comments
Closed

issues with vitejs #1744

flx-sta opened this issue Apr 29, 2021 · 18 comments

Comments

@flx-sta
Copy link
Contributor

flx-sta commented Apr 29, 2021

Describe the bug
When trying to use jsonforms with vitejs/vite

To Reproduce

  1. try to run a project including jsonforms with vitejs/vite

Expected behavior
Render my page with the given schema/uischema.

Screenshots
image
image

Browser (please complete the following information):

  • Chrome (up to date)

Used Setup (please complete the following information):

  • Framework: vuejs
  • RendererSet: super-simple barebone custom ones

Additional context
This seems to be an issue connected to the <JsonForms/> component.
As long as I don't import that one it works

@flx-sta
Copy link
Contributor Author

flx-sta commented Apr 30, 2021

Woraround

I found a workaround solution for now but I don't know all side effects this causes:

⚠️ I've provided a different workaround recently. That one would break any build! Use the up to date one! ⚠️

// vite.config.ts

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  define: {
    'process.platform': null,
    'global.setImmediate': null,
  },
});

@sdirix
Copy link
Member

sdirix commented Apr 30, 2021

Can you check the content of url.js where process is accessed? This is probably the url dependency of @jsonforms/core, however as far as I can see process is never called in its source file. So probably something goes wrong during transpiling / bundling.

@flx-sta
Copy link
Contributor Author

flx-sta commented Apr 30, 2021

@sdirix

url.js
  "use strict";
  
  let isWindows = /^win/.test(process.platform),
      forwardSlashPattern = /\//g,
      protocolPattern = /^(\w{2,}):\/\//i,
      url = module.exports;
  
  // RegExp patterns to URL-encode special characters in local filesystem paths
  let urlEncodePatterns = [
    /\?/g, "%3F",
    /\#/g, "%23",
  ];
  
  // RegExp patterns to URL-decode special characters for local filesystem paths
  let urlDecodePatterns = [
    /\%23/g, "#",
    /\%24/g, "$",
    /\%26/g, "&",
    /\%2C/g, ",",
    /\%40/g, "@"
  ];
  
  exports.parse = require("url").parse;
  exports.resolve = require("url").resolve;
  
  /**
   * Returns the current working directory (in Node) or the current page URL (in browsers).
   *
   * @returns {string}
   */
  exports.cwd = function cwd () {
    return process.browser ? location.href : process.cwd() + "/";
  };
  
  /**
   * Returns the protocol of the given URL, or `undefined` if it has no protocol.
   *
   * @param   {string} path
   * @returns {?string}
   */
  exports.getProtocol = function getProtocol (path) {
    let match = protocolPattern.exec(path);
    if (match) {
      return match[1].toLowerCase();
    }
  };
  
  /**
   * Returns the lowercased file extension of the given URL,
   * or an empty string if it has no extension.
   *
   * @param   {string} path
   * @returns {string}
   */
  exports.getExtension = function getExtension (path) {
    let lastDot = path.lastIndexOf(".");
    if (lastDot >= 0) {
      return path.substr(lastDot).toLowerCase();
    }
    return "";
  };
  
  /**
   * Returns the hash (URL fragment), of the given path.
   * If there is no hash, then the root hash ("#") is returned.
   *
   * @param   {string} path
   * @returns {string}
   */
  exports.getHash = function getHash (path) {
    let hashIndex = path.indexOf("#");
    if (hashIndex >= 0) {
      return path.substr(hashIndex);
    }
    return "#";
  };
  
  /**
   * Removes the hash (URL fragment), if any, from the given path.
   *
   * @param   {string} path
   * @returns {string}
   */
  exports.stripHash = function stripHash (path) {
    let hashIndex = path.indexOf("#");
    if (hashIndex >= 0) {
      path = path.substr(0, hashIndex);
    }
    return path;
  };
  
  /**
   * Determines whether the given path is an HTTP(S) URL.
   *
   * @param   {string} path
   * @returns {boolean}
   */
  exports.isHttp = function isHttp (path) {
    let protocol = url.getProtocol(path);
    if (protocol === "http" || protocol === "https") {
      return true;
    }
    else if (protocol === undefined) {
      // There is no protocol.  If we're running in a browser, then assume it's HTTP.
      return process.browser;
    }
    else {
      // It's some other protocol, such as "ftp://", "mongodb://", etc.
      return false;
    }
  };
  
  /**
   * Determines whether the given path is a filesystem path.
   * This includes "file://" URLs.
   *
   * @param   {string} path
   * @returns {boolean}
   */
  exports.isFileSystemPath = function isFileSystemPath (path) {
    if (process.browser) {
      // We're running in a browser, so assume that all paths are URLs.
      // This way, even relative paths will be treated as URLs rather than as filesystem paths
      return false;
    }
  
    let protocol = url.getProtocol(path);
    return protocol === undefined || protocol === "file";
  };
  
  /**
   * Converts a filesystem path to a properly-encoded URL.
   *
   * This is intended to handle situations where JSON Schema $Ref Parser is called
   * with a filesystem path that contains characters which are not allowed in URLs.
   *
   * @example
   * The following filesystem paths would be converted to the following URLs:
   *
   *    <"!@#$%^&*+=?'>.json              ==>   %3C%22!@%23$%25%5E&*+=%3F\'%3E.json
   *    C:\\My Documents\\File (1).json   ==>   C:/My%20Documents/File%20(1).json
   *    file://Project #42/file.json      ==>   file://Project%20%2342/file.json
   *
   * @param {string} path
   * @returns {string}
   */
  exports.fromFileSystemPath = function fromFileSystemPath (path) {
    // Step 1: On Windows, replace backslashes with forward slashes,
    // rather than encoding them as "%5C"
    if (isWindows) {
      path = path.replace(/\\/g, "/");
    }
  
    // Step 2: `encodeURI` will take care of MOST characters
    path = encodeURI(path);
  
    // Step 3: Manually encode characters that are not encoded by `encodeURI`.
    // This includes characters such as "#" and "?", which have special meaning in URLs,
    // but are just normal characters in a filesystem path.
    for (let i = 0; i < urlEncodePatterns.length; i += 2) {
      path = path.replace(urlEncodePatterns[i], urlEncodePatterns[i + 1]);
    }
  
    return path;
  };
  
  /**
   * Converts a URL to a local filesystem path.
   *
   * @param {string}  path
   * @param {boolean} [keepFileProtocol] - If true, then "file://" will NOT be stripped
   * @returns {string}
   */
  exports.toFileSystemPath = function toFileSystemPath (path, keepFileProtocol) {
    // Step 1: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
    path = decodeURI(path);
  
    // Step 2: Manually decode characters that are not decoded by `decodeURI`.
    // This includes characters such as "#" and "?", which have special meaning in URLs,
    // but are just normal characters in a filesystem path.
    for (let i = 0; i < urlDecodePatterns.length; i += 2) {
      path = path.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
    }
  
    // Step 3: If it's a "file://" URL, then format it consistently
    // or convert it to a local filesystem path
    let isFileUrl = path.substr(0, 7).toLowerCase() === "file://";
    if (isFileUrl) {
      // Strip-off the protocol, and the initial "/", if there is one
      path = path[7] === "/" ? path.substr(8) : path.substr(7);
  
      // insert a colon (":") after the drive letter on Windows
      if (isWindows && path[1] === "/") {
        path = path[0] + ":" + path.substr(1);
      }
  
      if (keepFileProtocol) {
        // Return the consistently-formatted "file://" URL
        path = "file:///" + path;
      }
      else {
        // Convert the "file://" URL to a local filesystem path.
        // On Windows, it will start with something like "C:/".
        // On Posix, it will start with "/"
        isFileUrl = false;
        path = isWindows ? path : "/" + path;
      }
    }
  
    // Step 4: Normalize Windows paths (unless it's a "file://" URL)
    if (isWindows && !isFileUrl) {
      // Replace forward slashes with backslashes
      path = path.replace(forwardSlashPattern, "\\");
  
      // Capitalize the drive letter
      if (path.substr(1, 2) === ":\\") {
        path = path[0].toUpperCase() + path.substr(1);
      }
    }
  
    return path;
  };
  ```

</details>

@sdirix
Copy link
Member

sdirix commented Jun 24, 2021

With JSON Forms 3.0.0-alpha.0 Vitejs and JSON Forms now work almost completely out of the box. The only manual action still required is to install the tslib dependency. However we also plan to fix that for the full JSON Forms 3.0 release.

@flx-sta
Copy link
Contributor Author

flx-sta commented Jun 25, 2021

@sdirix so just a simple npm i tslib?

@sdirix
Copy link
Member

sdirix commented Jun 25, 2021

yes

@Druelik
Copy link

Druelik commented Apr 11, 2022

I migrated my building process to vitejs. While doing so i encountered a bug, which does not render custom renderer.

Using Jsonforms in dev enviroment works fine and everything is working as expected.

But if i build my app with vite for production , jsonforms stops rendering any components and doesn't log any error. Using the vue2-vanilla renderer works fine aswell as if you register the components manually first via the options api.

I made an reproduction repo if you want to take a look.
https://github.com/Druelik/jsonforms-custom-renderer-vite
npm run dev -> everything working as expected.
npm run build and afterwards npm run serve to preview -> does not render anything and doesnt log any error message.

For me it looks like the components in the renderers are not getting registered/compiled and vue doesn't resolve them correctly.

@emily-malone
Copy link

@Druelik did you find a fix for this?

@bishopandco
Copy link

I am stuck too. In production I can see the VerticalLayouts rendering but all of the inputs are just <!-----> html comments.

@emily-malone
Copy link

@bishopandco adding "rollup-plugin-cleanup" worked for me

@bishopandco
Copy link

Thanks @emily-malone, can you expand on your setup? did you add any additional configuration?

@bart-jaskulski
Copy link

@bishopandco I've been stuck with this problem as well.
The issue lies in vite's tree-shaking. If your component looks like those presented in vue-vanilla package, then vite has trouble to find out what whether your component was actually used or not. It's a bit larger trouble, I guess (as you have false-positives using jsonforms, which holds renderer component in variable, but this component is not registered).

Anyway, I've found two ways to work it out.
First, not recommended, you can register your component globally, in main file. Yet, I guess it's not really necessary to have it registered - direct import is crucial for vite to know about your dependency.
What I did was to split renderer entry (renderer + tester) from component file. My SFC file takes care of display, and in another, shared file I create definition of all renderers entries. This way those are imported, thus correctly resolved by vite.

Let me know, if you need more explanation and some code example perhaps.

@bishopandco
Copy link

@bart-jaskulski thanks. I managed to get it all working by creating a brand new app, installing jsonforms first, and then building up from there. After seeing @sdirix's comment that it's working out of the box ... i went back to the box.

We are splitting our renderers up like that as well. Like this: eclipsesource/jsonforms-vue-seed#13

@sdirix
Copy link
Member

sdirix commented Sep 1, 2022

There is a lot of discussion here but if I understand correctly then there is no actual issue with JSON Forms, right? Or did I miss something and there is something which could be improved?

@bart-jaskulski
Copy link

Hi @sdirix!

I think it more likely Vite issue, as imports from external package are working correctly. I don't event think that DispatchRenderer could work better to somehow inform users about possible issue, because that component receives renderers correctly.

Nevertheless, I would be nice to put information about known bug in documentation with possible workarounds, as it can save a few hours and unpleasant surprise when switching to production environment.

I'll post issue on Vite's board later this week, linking to this issue.

@sdirix
Copy link
Member

sdirix commented Nov 8, 2022

I'll close this issue for now. Feel free to reopen if you disagree.

@sdirix sdirix closed this as completed Nov 8, 2022
@cesardddp
Copy link

@bishopandco I've been stuck with this problem as well. The issue lies in vite's tree-shaking. If your component looks like those presented in vue-vanilla package, then vite has trouble to find out what whether your component was actually used or not. It's a bit larger trouble, I guess (as you have false-positives using jsonforms, which holds renderer component in variable, but this component is not registered).

Anyway, I've found two ways to work it out. First, not recommended, you can register your component globally, in main file. Yet, I guess it's not really necessary to have it registered - direct import is crucial for vite to know about your dependency. What I did was to split renderer entry (renderer + tester) from component file. My SFC file takes care of display, and in another, shared file I create definition of all renderers entries. This way those are imported, thus correctly resolved by vite.

Let me know, if you need more explanation and some code example perhaps.

Hi, can i have examples? i make my renders from vue-vanila repo and now im stuck in this issue

@sdirix
Copy link
Member

sdirix commented Apr 9, 2024

HI @cesardddp,

Remove the entry and tester from ".vue" files and only export the renderer component there. Then construct the tester and renderer in some other regular Javascript/Typescript file and use that in JSON Forms. That should fix the issue for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants