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

Some advice for bundling this with Rollup as an esm library #10

Open
kaphula opened this issue Dec 15, 2021 · 4 comments
Open

Some advice for bundling this with Rollup as an esm library #10

kaphula opened this issue Dec 15, 2021 · 4 comments

Comments

@kaphula
Copy link

kaphula commented Dec 15, 2021

Hey,

I was able to make use of this library in my project using the Ammo as es6 module import method when I launched my application through Webpack5 development server with libraryTarget set to window.

My project is a graphics library to be used inside the browser to execute custom javascript code. I use Rollup to generate the library file as ECMAScript module (esm format). When I build my project as esm library with Rollup and try to use it in a browser I get the following error Uncaught TypeError: Cannot set properties of undefined (setting 'Ammo'). This issue does not happen with other libraries such as Threejs and Pixijs which I also use. I was wondering if you are aware of some technical limitation that prevents using ammojs-typed as a bundled browser library the way I described?

I also tried the Ammo as dynamic import method but could not even get that to work in Webpack5. I copied the ammo.js and ammo.d.ts files to my TypeScript source folder and referred to their paths as shown in the README. Even though everything else seemed to be fine, I got an error saying Module.default() is not a function. Then I tried Module.default but that returned undefined, so I could get any further with that.

@giniedp
Copy link
Owner

giniedp commented Dec 16, 2021

What does your rollup file and your tsconfig.json look like? Have you tried the allowSyntheticDefaultImports compiler option?
https://www.typescriptlang.org/tsconfig#allowSyntheticDefaultImports

you might want to ask this question on the original ammojs project. This one just adds type annotations without modifying the original code.

@kaphula
Copy link
Author

kaphula commented Dec 16, 2021

Yeah, I have the allowSyntheticDefaultImports enabled but it does not seem to make a difference.

I figured I'd ask here first since there were different methods listed for initializing the ammo.js on the readme. I must admit, I have a fairly limited understanding of the Javascript building processes. There's just so many different options, tools and plugins for this stuff.

Here are the configs. I appreciate if you have suggestion for a solution, but as this is somewhat out of the scope of this repository, you can close this issue if you want.

rollup.config.js:

import commonjs from '@rollup/plugin-commonjs'
import glslify from 'rollup-plugin-glslify'
import builtins from 'rollup-plugin-node-builtins'
import resolve from '@rollup/plugin-node-resolve'
import { terser } from "rollup-plugin-terser";
import smartAsset from "rollup-plugin-smart-asset"
import typescript from "rollup-plugin-typescript2";
import nodeResolve from "@rollup/plugin-node-resolve";

const smartAssetOpts = {
  extensions: ['.png', '.glb', '.mp3', '.ogg', '.jpg', '.jpeg'],
  assetsPath: 'data',
  publicPath: `./data/`,
  url: 'copy',
  keepImport: true,
  useHash: true,
  keepName: true,
  sourceMap: false
}

export default [
  {
    input: 'src/index.js',
    plugins: [
      glslify({basedir: 'src/shaders'}),
      typescript(),
      nodeResolve({preferBuiltins: false}),
      resolve(),
      commonjs(),
      builtins(),
      terser(),
      smartAsset(smartAssetOpts)
    ],
    output: [
      {
        format: 'esm',
        file: 'build/lib.module.js',
        indent: '\t',
        intro: 'const global = window;',
      },
    ],
  },
]

tsconfig.json:

{
  "compilerOptions": {
    "typeRoots": ["node_modules/ammojs-typed/ammo/ambient"], 
    "allowSyntheticDefaultImports": true,         
    "esModuleInterop": true,             

    "target": "es5",                                 
    "lib": ["dom", "es2015"],                       
    "moduleResolution": "node",                    
    "allowUmdGlobalAccess": true,                 
    "resolveJsonModule": true,                   
    "declaration": true,                             
    "sourceMap": true,                              
    "outDir": "./dist/",                           
    "forceConsistentCasingInFileNames": true,   
    "strict": true,                            
    "noImplicitAny": true,                    
    "strictNullChecks": true,                
    "skipLibCheck": true                    
  },
  "include": [
    "src/**/*",
    "assets.d.ts"
  ],
  "exclude": [
    "node_modules",
    "lib",
    "**/*.test.ts"
  ]
}

Quick update on the dynamic import method:

I managed to get the dynamic import working on my Webpack configuration with this:

import("ammojs-typed")                        // use dynamic import
    .then((Module) => Module.default())      // bootstrap ammo.js
    .then((ammo) => {
        const t = new ammo.btTransform();
        console.log("data from ammojs-typed: " + JSON.stringify(t))
        // let v1: Ammo.btVector3 = null
    })

So the import refers to the npm package directly and not ammo.js as demonstrated in the README. However, when this is rolled through the Rollup build, I get greeted with this error: Uncaught (in promise) TypeError: Cannot add property Ammo, object is not extensible

I also updated my Rollup configuration to use rollup-plugin-esbuild to replace the rollup-plugin-terser and rollup-plugin-typescript2 but the issue still persist when it comes to ammo.js.

@kaphula
Copy link
Author

kaphula commented Dec 18, 2021

It seems the only solution for this problem currently is to provide the ammo.js module externally to your program by dynamically injecting the dom with a script tag that references the ammo.js module or by directly making the ammo.js available through script tags from your html file.

If used with TypeScript, the ambient types of this repository can be used to make the TS compiler happy for the real code that utilizes functionality from ammo.js.

You can close this issue if there's nothing else you would like to add or suggest. I feel like this issue needs deeper fixing on the ammo.js side and there's not much we can do to make the bundling work because other people are facing similar issues.

@Dezzmeister
Copy link

Dezzmeister commented Sep 17, 2023

Yeah, I have the allowSyntheticDefaultImports enabled but it does not seem to make a difference.

I figured I'd ask here first since there were different methods listed for initializing the ammo.js on the readme. I must admit, I have a fairly limited understanding of the Javascript building processes. There's just so many different options, tools and plugins for this stuff.

Here are the configs. I appreciate if you have suggestion for a solution, but as this is somewhat out of the scope of this repository, you can close this issue if you want.

rollup.config.js:

import commonjs from '@rollup/plugin-commonjs'
import glslify from 'rollup-plugin-glslify'
import builtins from 'rollup-plugin-node-builtins'
import resolve from '@rollup/plugin-node-resolve'
import { terser } from "rollup-plugin-terser";
import smartAsset from "rollup-plugin-smart-asset"
import typescript from "rollup-plugin-typescript2";
import nodeResolve from "@rollup/plugin-node-resolve";

const smartAssetOpts = {
  extensions: ['.png', '.glb', '.mp3', '.ogg', '.jpg', '.jpeg'],
  assetsPath: 'data',
  publicPath: `./data/`,
  url: 'copy',
  keepImport: true,
  useHash: true,
  keepName: true,
  sourceMap: false
}

export default [
  {
    input: 'src/index.js',
    plugins: [
      glslify({basedir: 'src/shaders'}),
      typescript(),
      nodeResolve({preferBuiltins: false}),
      resolve(),
      commonjs(),
      builtins(),
      terser(),
      smartAsset(smartAssetOpts)
    ],
    output: [
      {
        format: 'esm',
        file: 'build/lib.module.js',
        indent: '\t',
        intro: 'const global = window;',
      },
    ],
  },
]

tsconfig.json:

{
  "compilerOptions": {
    "typeRoots": ["node_modules/ammojs-typed/ammo/ambient"], 
    "allowSyntheticDefaultImports": true,         
    "esModuleInterop": true,             

    "target": "es5",                                 
    "lib": ["dom", "es2015"],                       
    "moduleResolution": "node",                    
    "allowUmdGlobalAccess": true,                 
    "resolveJsonModule": true,                   
    "declaration": true,                             
    "sourceMap": true,                              
    "outDir": "./dist/",                           
    "forceConsistentCasingInFileNames": true,   
    "strict": true,                            
    "noImplicitAny": true,                    
    "strictNullChecks": true,                
    "skipLibCheck": true                    
  },
  "include": [
    "src/**/*",
    "assets.d.ts"
  ],
  "exclude": [
    "node_modules",
    "lib",
    "**/*.test.ts"
  ]
}

Quick update on the dynamic import method:

I managed to get the dynamic import working on my Webpack configuration with this:

import("ammojs-typed")                        // use dynamic import
    .then((Module) => Module.default())      // bootstrap ammo.js
    .then((ammo) => {
        const t = new ammo.btTransform();
        console.log("data from ammojs-typed: " + JSON.stringify(t))
        // let v1: Ammo.btVector3 = null
    })

So the import refers to the npm package directly and not ammo.js as demonstrated in the README. However, when this is rolled through the Rollup build, I get greeted with this error: Uncaught (in promise) TypeError: Cannot add property Ammo, object is not extensible

I also updated my Rollup configuration to use rollup-plugin-esbuild to replace the rollup-plugin-terser and rollup-plugin-typescript2 but the issue still persist when it comes to ammo.js.

The object is not extensible error occurs because you're trying to bootstrap ammo with Module: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cant_define_property_object_not_extensible

I ran into the same problem and solved it by creating a new object with Module as the prototype, like this:

import("ammojs-typed")
    .then(Module => Object.create(Module).default())
    .then(ammo => initializeStuff(ammo));

This should work for your production build. It worked for me using Vite, which uses Rollup.

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

No branches or pull requests

3 participants