Archived

This forum has been archived. Please start a new discussion on GitHub.

Using Vue with Ice JS

Hi,

I've been using the Ice JS and TS bindings using Vue.js for a browser-based test project, but it has sometimes been very hard to get things to work when it comes to bundling/importing. On this forum (or on github) there's a few threads about people using React/Angular that were somewhat helpful.

For starters, I'd like to not include Ice via html script src lines, but via import statements in the code, the same way all other packages are used (eg axios, vuetify, etc). I assume that means that the vue development environment (vue-cli or vite) will have to bundle Ice somehow. My understanding here is limited, I've seen many references to the Ice Gulp builder, but I have no idea if that is needed when already using webpack or esbuild as part of the vue dev system.

I've made two mini Vue3 based Ice testers (see here), one using vue-cli, one using Vite. My idea here was to use these to provide minimal examples of the issues I was facing in my much bigger test-project. I'm trying to switch to Vite, so the vue3-vite demo would be of most interest.

In my test repo, I've just run slice2js manually without any Gulp use. My Hello.ice contains js:es6-module, so that it can be imported nicely by modern JS, instead of using require. The Ice libs are all commonjs as far as I know.

The Hello.js is modified to remove the problematic import statement:

//import { Ice } from "ice";
import '/node_modules/ice/lib/Ice.js'

If you revert that, or recompile the slice file, you'll get an import error:

Uncaught SyntaxError: import not found: Ice

Which as far as I can tell is because Ice.js is commonjs and does not export the proper object.

  • Do you have any idea on how to get the 'import {Ice}' to work?
  • Is your gulp build system required for it to work?

Cheers,

Rob

Comments

  • xdm
    xdm La Coruña, Spain

    Hi Rob,

    The Ice for JavaScript browser version from node_modules/ice/lib/Ice.js it creates a global ice object.

    I was able to get your vue3-vite example to work, with a few changes

    jose@DESKTOP-G5LGUQJ MINGW64 ~/source/repos/vue-ice-tests/vue3-vite (main)
    $ git diff
    diff --git a/vue3-vite/index.html b/vue3-vite/index.html
    index 606464d..2e39b52 100644
    --- a/vue3-vite/index.html
    +++ b/vue3-vite/index.html
    @@ -5,14 +5,10 @@
         <link rel="icon" href="/favicon.ico" />
         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
         <title>Vite App</title>
    +    <script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/ice/3.7.70/Ice.min.js"></script>
       </head>
       <body>
         <div id="app"></div>
    -    <!-- <script src="node_modules/ice/lib/Ice.js"></script>
    -         <script src="node_modules/ice/lib/Glacier2.js"></script>
    -         <script src="node_modules/ice/lib/IceGrid.js"></script>
    -         <script src="/src/slice/Hello.js"></script>
    -     -->
         <script type="module" src="/src/main.js"></script>
       </body>
     </html>
    diff --git a/vue3-vite/src/slice/Hello.js b/vue3-vite/src/slice/Hello.js
    index c6c436b..f0c128b 100644
    --- a/vue3-vite/src/slice/Hello.js
    +++ b/vue3-vite/src/slice/Hello.js
    @@ -16,8 +16,7 @@
     /* eslint-disable */
     /* jshint ignore: start */
    
    -import '/node_modules/ice/lib/Ice.js'
    -//import { Ice } from "ice";
    +import { Ice } from "ice";
    
     const _ModuleRegistry = Ice._ModuleRegistry;
     const Slice = Ice.Slice;
    diff --git a/vue3-vite/vite.config.js b/vue3-vite/vite.config.js
    index ac6b492..91f0af9 100644
    --- a/vue3-vite/vite.config.js
    +++ b/vue3-vite/vite.config.js
    @@ -1,33 +1,21 @@
     import { defineConfig } from 'vite'
     import vue from '@vitejs/plugin-vue'
    
    -//import { viteCommonjs } from '@originjs/vite-plugin-commonjs'
    -import { esbuildCommonjs } from '@originjs/vite-plugin-commonjs'
    -
     // https://vitejs.dev/config/
     export default defineConfig({
    +  assetsInclude: ['**/Ice.js'],
       plugins: [
         vue()
    -//    viteCommonjs({exclude: 'ice'})
       ],
       build: {
         rollupOptions: {
           external: ['ice'],
           output: {
    +        format: 'iife',
             globals: {
               ice: 'ice',
             },
    -      },
    -    }
    -  },
    -
    -  optimizeDeps: {
    -    exclude: ['ice'],
    -
    -    esbuildOptions:{
    -      plugins:[
    -        esbuildCommonjs(['ice'])
    -      ]
    +      }
         }
       }
     })
    

    The changes:

    • In index.html I added a script tag to include Ice.js from the CDN, but you can use any path that is available in your server.
    • in Hello.js keep the import { Ice } from "ice"; as generated by slice2js
    • In vite.config.js, add Ice.js to the assets, so that it is not processed by the build, and set rollup format to format: 'iife',

    Not sure if this will work with your real scenario.

    Cheers,
    Jose

  • Hi Jose,

    Thanks for looking into this! Your result is very similar to what worked for me too, but I'm trying to avoid direct html script includes, because then serving them will become more tricky, for example in a vite build/preview cycle (rather than 'npm run dev'). The app environment will be offline (LAN only), so no CDNs. I could serve the Ice js files from a known URL, but then perhaps I would need a different URL for development and production, etc. It would be much nicer if the Ice files were bundled by webpack/rollup like all the other npm packages.

    For example, to use the 'axios' package, you can just do "import axios from 'axios'", and rollup will bundle the axios js files. I haven't been able to find out yet what makes the 'ice' package different from 'axios' in that aspect.

    Do you have any suggestions?

    Cheers,
    Rob

    PS. As you propably saw in my vite.config.js, I'm pretty confused about all the bundling stuff and various JS module types. If anyone else is in a similar situation reading this thread, this is quite a good explanation on the history of JS modules.

  • xdm
    xdm La Coruña, Spain

    Hi Rob,

    There are two JavaScript modules with Ice, one for working with NodeJS run-time and one for the browsers, the NodeJS package on npm includes both, the browser applications need to use the library bundles from node_modules/ice/lib/ and NodeJS applications can use require('ice').

    The source is mostly the same, but the browser bundles has strip away all the dynamic imports, and includes the WebSocket transport instead of the TCP transport used by NodeJS version.

    The browser bundle is an IIFE that defines the global 'ice' object, this allow the generated files use import { Ice } from "ice"; when 'ice" is defined as a external global with rollup or webpack.

    I could serve the Ice js files from a known URL, but then perhaps I would need a different URL for development and production, etc.

    One workaround you can try is to copy Ice.js to the public dir, and vite would make it accessible as /Ice.js, you need to keep it assetsInclude to avoid vite to process the file.

    I have create an issue in our github repository to improve this, and make the import simpler see https://github.com/zeroc-ice/ice/issues/1343

  • Hi Jose,

    I've pushed the changes you made, plus one more import fix in App.vue, and changed index.html to fetch from a copy of Ice.min.js in public/. This works for the 'npm run build; npm run preview' case, but fails in dev mode with an error that I've seen many times before in my endless iterations to make this work:

    Uncaught TypeError: m.require is not a function
        require ModuleRegistry.js:25
        require ModuleRegistry.js:23
        js Ice.js:7
        __require2 chunk-2Y2CNEUS.js:10
        js index.js:5
        __require2 chunk-2Y2CNEUS.js:10
        <anonymous> ice:1
    

    If I do a 'npx vite --force' instead of 'npm run dev' just to make sure things are re-initialized (similar to 'rm -rf node_modules/.vite/), it is probably already problematic that vite is messing with the ice package:

    [laprob] ~/vue/ice-minimal/vue3-vite> npx vite --force
    Pre-bundling dependencies:
      vue
      ice
    (this will be run only when your dependencies or config have changed)
    
      vite v2.8.3 dev server running at:
      ..snip
    

    This is what I was trying to work around with the esbuildCommonjs stuff in vite.config.js, but I have no idea if that is appropriate or not.. If I put that back in, vite dev will not pre-bundle ice, but then I'm back to the previous error:

    Uncaught SyntaxError: import not found: Ice     (in Hello.js)
    

    Even though the Ice.min.js is fetched OK according to the browser devtools.

    Cheers,
    Rob

  • xdm
    xdm La Coruña, Spain

    Hi Rob,

    You are right this doesn't work with the dev build, I didn't try this before. So far I have not yet found a way to get the dev build to work with esbuild.

  • xdm
    xdm La Coruña, Spain

    Hi Rob,

    I have been working on update "ice" module to work with Vite and Vue. I already got your samples working with this updated module, without the need of special configuration. We will publish an updated module once we do some more testing.

    Cheers,
    Jose

  • Hi Jose,

    Thanks, I just read the progress in your github issue too. That's great :)
    My next question would have been if Ice can be compiled as esm modules everywhere, but it seems like you're doing something similarish.

    Cheers!
    Rob

  • xdm
    xdm La Coruña, Spain

    Hi Rob,

    I just published and update "ice" package to NPM ice@3.7.71 that include the fixes for this issue, once you update you should be able to use import { Ice } from "ice" in your vite setup without additional configuration.

  • Hi Jose,

    After updating and cleaning up my tester app, everything works well for the vite based tester. No more complicated configuration needed, great!

    For the vue-cli based tester here, there's still an issue. If I remove the webpack 'externals' setting from vue.config.js, it looks like it tries to load node code:

    error  in ./node_modules/ice/src/Ice/Debug.js
    
    Module not found: Error: Can't resolve 'fs' in '/home/rob/vue/ice-minimal/vue3-cli/node_modules/ice/src/Ice'
    
    error  in ./node_modules/ice/src/Ice/TcpTransceiver.js
    
    Module not found: Error: Can't resolve 'net' in '/home/rob/vue/ice-minimal/vue3-cli/node_modules/ice/src/Ice'
    

    If I leave the webpack externals setting, another error pops up:

    Uncaught TypeError: ice__WEBPACK_IMPORTED_MODULE_4__.Ice is undefined
        <anonymous> Hello.js:20
        js app.js:74
        __webpack_require__ app.js:277
       ..snip..
    

    I've been digging through the files to see if there was some leftover junk from testing, but it seems everything is as it should be..

    Cheers!
    Rob

  • xdm
    xdm La Coruña, Spain

    I added some notes here, basically with WebPack and Rollup you need to provide a mock for "fs" and "net" modules that are only used when running in NodeJS, with Vite there is no additional setup it handles this by default, see the linked examples.

  • OK thanks, I added fallback options to vue.config.js and now all is well :)