Interact.js: Tree shaking

Created on 4 Mar 2020  路  28Comments  路  Source: taye/interact.js

This library is great but very big. Is it possible to build a smaller version with only basic draggable or draggable and dropzone features?

Most helpful comment

With version 1.9.0, using webpack, browserify, etc. you can do

import '@interactjs/actions/use/drag'
import '@interactjs/modifiers/use'
import '@interactjs/inertia/use'
import '@interactjs/auto-start/use'
import interact from '@interactjs/interact'

interact('.draggable').draggable({})

And in the latest browsers:

<script type="module">
import 'https://cdn.jsdelivr.net/npm/@interactjs/actions/use/drag.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/modifiers/use/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/inertia/use/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/auto-start/use/index.js'
import interact from 'https://cdn.jsdelivr.net/npm/@interactjs/interact/index.js'

interact('.draggable').draggable({})
</script>

There's a warning in the console (with NODE_ENV !== 'production') because I'd like to get some more feedback before writing docs and committing to supporting this feature. I'll leave this issue open in the mean time.

All 28 comments

It's not stable yet, but you can import each of the internal packages selectively and set things up the way you need. Have a look at https://github.com/taye/interact.js/blob/master/@interactjs/interact/index.ts#L1 and https://github.com/taye/interact.js/blob/master/@interactjs/interactjs/index.ts for how it's done for the bundled library.

Thanks. Maybe I'll wait for the official version because there's too much typescript involved and it takes long time to get to know what really is needed in each package.

The syntax could be something like this: import {draggable, dropzone} from 'interact'

I like that idea. Expanding on it, I think I might make a package called @interactjs/use which would add each plugin that's imported from it so you would do something like:

npm install --save @interactjs/use @interactjs/interact

import '@interactjs/use/draggable'
import '@interactjs/use/modifiers'
import '@interactjs/use/inertia'
import interact from '@interactjs/interact'

interact('.draggable')

I recently did some work to allow plugins to be added in different orders and to make them add the plugins that they need (eg. drop will also install drag) so with this solution, it should be fairly simple to make custom builds.

Thanks for the feedback!

With version 1.9.0, using webpack, browserify, etc. you can do

import '@interactjs/actions/use/drag'
import '@interactjs/modifiers/use'
import '@interactjs/inertia/use'
import '@interactjs/auto-start/use'
import interact from '@interactjs/interact'

interact('.draggable').draggable({})

And in the latest browsers:

<script type="module">
import 'https://cdn.jsdelivr.net/npm/@interactjs/actions/use/drag.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/modifiers/use/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/inertia/use/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/auto-start/use/index.js'
import interact from 'https://cdn.jsdelivr.net/npm/@interactjs/interact/index.js'

interact('.draggable').draggable({})
</script>

There's a warning in the console (with NODE_ENV !== 'production') because I'd like to get some more feedback before writing docs and committing to supporting this feature. I'll leave this issue open in the mean time.

Wow, great work!

I just tried tree-shaking interactjs with a simple Vue project. In dev mode everything works fine (npm run serve), but building the app the following error occurs:

ReferenceError: can't access lexical declaration `e' before initialization

I use interact('.draggable').draggable(...) as well as interact('.draggable').unset(...).

@johannschopplich what bundler are you using?

What Vue CLI uses, Webpack. I probably have to turn on source map generation, the error it throws is untrackable.

The webpack issue should be fixed in version 1.9.2

It is indeed fixed. Thank you!

It worked two days ago but throws these errors now:

ERROR  Failed to compile with 4 errors                                                                                                                                           

These dependencies were not found:

* @interactjs/actions/use/drag in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/d
ist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/InteractDraggable.vue?vue&type=script&lang=js&
* @interactjs/auto-start/use in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/dis
t/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/InteractDraggable.vue?vue&type=script&lang=js&
* @interactjs/inertia/use in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/c
js.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/InteractDraggable.vue?vue&type=script&lang=js&
* @interactjs/modifiers/use in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist
/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/InteractDraggable.vue?vue&type=script&lang=js&

To install them, you can run: npm install --save @interactjs/actions/use/drag @interactjs/auto-start/use @interactjs/inertia/use @interactjs/modifiers/use

Removing the @ doesn't work either. I'm puzzled.

Did you add the @interactjs/actions @interactjs/use @interactjs/inertia packages to your project as well as the required peer dependencies? You can also just install the @interactjs/interactjs package which depends on all the others.

I installed the package via npm i @interactjs/interact. The corresponding folders (like @interactjs/actions/use/drag) contain only the TypeScript definitions, no compatible JS scripts. Maybe Webpack then can't include them in its transpiler process.

The published packages definitely have the .js files in them 馃.

The @interactjs/interact package doesn't have any of the other packages in its dependencies so I think you'll need to install them explicitly. (Ignore my earlier advice about installing only @interactjs/interactjs (with "js" at the end). That's not a good idea if you're using pnpm)`

I'm sorry, but I can't resolve it. I have tried multiple ways. When installing @interactjs/actions for example, the use folder still doesn't contain .js files. Installing peer dependencies does work, but the same error as before is thrown.

You may verify that the package doesn't contain use/*.js files: https://registry.npmjs.org/@interactjs/actions/-/actions-1.9.3.tgz

Also: @interactjs/use doesn't seem to have a package. At least npm says so.

Excerpt of current configuration:

"dependencies": {
  "@interactjs/actions": "^1.9.3",
  "@interactjs/inertia": "^1.9.3",
  "@interactjs/interact": "^1.9.3",
  "@interactjs/modifiers": "^1.9.3"
},
"devDependencies": {
  "@interactjs/core": "^1.9.3",
  "@interactjs/offset": "^1.9.3",
  "@interactjs/types": "^1.9.3",
  "@interactjs/utils": "^1.9.3",
}

@interactjs/use was a typo, sorry.

You're right, they're missing. I'll fix that.

Wonderful, working now. Thank you!

Btw., npm i @interactjs/interactjs includes all modules and peer dependencies. Easy setup.

In old code I use:

import interact from 'interactjs'
node.dnd = interact(this.$el)
node.dnd.draggable(dragOptions)

What is the new syntax?

I've done some rearranging to reduce the number of packages you'll have to install explicitly.

npm i @interactjs/interact @interactjs/actions @interactjs/auto-start @interactjs/inertia @interactjs/modifiers @interactjs/dev-tools
# and other packages you'd like to use such as @interactjs/auto-scroll @interactjs/pointer-events @interactjs/reflow
import '@interactjs/actions/use'
import '@interactjs/auto-start/use'
import '@interactjs/inertia/use'
import '@interactjs/modifiers/use'
import '@interactjs/dev-tools/use'

import interact from '@interactjs/interact'

interact('.draggable')

@taye Do you have any timeline on when this will go into the official library?

@holgersindbaek I can't promise anything, but I hope to have this documented and stable by early next month. You can already use the imports with the latest version already on npm, but there's a small chance that the module naming will change.

I've removed the use/ from the plugin import paths. In v1.9.12, you can import with a simpler:

import '@interactjs/actions'
import '@interactjs/auto-start'
import '@interactjs/inertia'
import '@interactjs/modifiers'
import '@interactjs/dev-tools'

import interact from '@interactjs/interact'

interact('.draggable')

And in modern browsers without a bundler:

import 'https://cdn.jsdelivr.net/npm/@interactjs/actions/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/auto-start/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/inertia/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/modifiers/index.js'
import 'https://cdn.jsdelivr.net/npm/@interactjs/dev-tools/index.js'

import interact from 'https://cdn.jsdelivr.net/npm/@interactjs/interact/index.js'

This will likely be the last breaking change I make for this feature.

Wonderful. Thanks for keeping us in the loop!

I plan on making one more change: I'd like to change the .min.js extension of the unminified files to .dev.js and the minified files to .production.min.js or something similar. I think it provides a hint that the non minified files offer advantages for development over the minified files (which they do).

I'm welcome to thoughts or suggestions on the naming!

Great idea! My two cents: I'd prefer .prod.js over .production.min.js and imply that production code _is_ minified. Also .dev.js pairs nicely with .prod.js regarding the suffix length and readability. For example Google follows this schema for their Workbox script bundles.
I haven't seen .mjs in a while, but it would also suit development environment purposes I guess. Although .dev.js is much more declarative.

I'm just a newbie in TypeScript but from what I read in the official docs (and from what I understand), wrapping modules with namespaces and exporting namespaces should be avoided:

Here is also a stackoverflow post on the same subject:

Just my 0.02

Hello :wave:

Thanks @johannschopplich for your feedback. I've decided to use .prod.js for production files and leave the development files with just a .js extension for simpler imports as these files are minified, but non bundled ES modules. I'd consider changing the extensions of the bundles in the unscoped interactjs package, but it might break things for people using public CDNs such as jsdelivr.

I've made these changes in #857. The PR also introduces a babel plugin to change all scoped @interact/* imports from the dev files to their .prod.js versions.

Feedback before I merge the PR is very welcome :slightly_smiling_face:

@taye Gotta say, how you handle issues and therefore your community is wonderful! 馃檪

I think those changes sound great. Having no suffix is probably the best DX, since just the extension is common practive for imports.

I've merged #857, released version 1.10.0, and updated the docs at https://interactjs.io/docs/installation and https://interactjs.io/docs/tooling. I think tree shaking should now work nicely and this issue can be closed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

freefalling picture freefalling  路  3Comments

idmadj picture idmadj  路  3Comments

ttback picture ttback  路  8Comments

gossi picture gossi  路  5Comments

kongaraju picture kongaraju  路  6Comments