Migrating from v1 to v2
Apply the following steps to your project to ensure a smooth upgrade from v1 to v2.
Update imports
Exports have been simplified in the v2 version, there are now 2 main entry points: @studiometa/js-toolkit
and @studiometa/js-toolkit/utils
. Nested import can still be used but will certainly be removed in a later version, so use them with caution.
All deep nested imports can be rewritten to import the named exports from one of these two entrypoints. The Base
class, the decorators, the services and the helpers can be imported from the root entry:
- import Base from '@studiometa/js-toolkit';
- import { withMountWhenInView } from '@studiometa/js-toolkit/decorators';
- import { useScroll } from '@studiometa/js-toolkit/services';
- import { importWhenVisible } from '@studiometa/js-toolkit/helpers';
+ import {
+ Base,
+ withMountWhenInView,
+ useScroll,
+ importWhenVisible
+ } from '@studiometa/js-toolkit';
All utilities can be imported from the @studiometa/js-toolkit/utils
entry:
- import debounce from '@studiometa/js-toolkit/utils/debounce';
- import throttle from '@studiometa/js-toolkit/utils/throttle';
+ import { debounce, throttle } from '@studiometa/js-toolkit/utils';
math utilities
- import damp from '@studiometa/js-toolkit/utils/math/damp';
- import clamp01 from '@studiometa/js-toolkit/utils/math/clamp01';
+ import { damp, clamp01 } from '@studiometa/js-toolkit/utils';
css utilities
- import matrix from '@studiometa/js-toolkit/utils/css/matrix';
- import transition from '@studiometa/js-toolkit/utils/css/transition';
+ import { matrix, transition } from '@studiometa/js-toolkit/utils';
Deleted exports
The styles
and classes
exports of the /utils/css/
namespace have been deleted as they are internal utils.
object utilities
Deleted exports
The autoBind
, getAllProperties
and isObject
exports of the /utils/object
namespace have been deleted as they are internal utils.
history API utilities
- import { push, replace, objectToURLSearchParams } from '@studiometa/js-toolkit/utils/history';
+ import {
+ historyPush,
+ historyReplace,
+ objectToURLSearchParams ,
+ } from '@studiometa/js-toolkit/utils';
Define all refs
In the v1, all elements with a data-ref="refName"
inside the scope of a data-component
were registered as refs with the config.refs
definition used to display warnings when a ref was found but not defined.
The v2 is more strict and will only look up refs defined in the config.refs
property, without warning if some extra refs exists in the scope of the component.
HTML
<div data-component="Foo">
<div data-ref="one"></div>
<div data-ref="two"></div>
</div>
v1
class Foo extends Base {
static config = {
name: 'Foo',
refs: ['one'],
};
mounted() {
console.log(this.$refs); // Before: { one: HTMLElement, two: HTMLElement }
}
}
v2
class Foo extends Base {
static config = {
name: 'Foo',
refs: ['one'],
};
mounted() {
console.log(this.$refs); // Before: { one: HTMLElement }
}
}
To fix this issue, make sure to define all the refs used by a component:
class Foo extends Base {
static config = {
name: 'Foo',
- refs: ['one'],
+ refs: ['one', 'two'],
};
Update $on
callbacks
The $on
instance method can be used to listen to events emitted by a component. The v2 uses the EventTarget
API with addEventListener
and removeEventListener
to manage these events.
Custom data attached to an emitted event can now be found in the event.detail
propery:
- this.$on('event', (one, two) => {
+ this.$on('event', (event) => {
+ const [one, two] = event.detail;
console.log({ one, two })
});
this.$emit('event', 1, 2);
Tip
When using the Events Hooks API, the value of event.detail
is used as parameters for each method. The changes are only for the $on(event, callback)
instance method.
Replace $once
The $once
instance method has been removed since the EventTarget
API implements this functionnality by passing a once
option to the addEventListener
method.
- this.$once('event', () => {
+ this.$on('event', () => {
// do something once.
- })
+ }, { once: true })
Use $children
instead of $refs
to access child component instances
Before the v2, $refs
properties could be instances or array of instances of children components when setting the data-ref="refName"
attribute on a child component root element. This is no longer the case as $refs
properties are now either a single DOM element or an array of DOM elements.
HTML
<div data-component="Parent">
<div data-ref="child" data-component="Child"></div>
</div>
v1
class Parent extends Base {
static config = {
name: 'Parent',
refs: ['child'],
components: {
Child,
},
};
mounted() {
console.log(this.$refs); // { child: Child }
console.log(this.$refs.child instanceof Child); // true
}
}
v2
class Parent extends Base {
static config = {
name: 'Parent',
refs: ['child'],
components: {
Child,
},
};
mounted() {
console.log(this.$refs); // { child: HTMLDivElement }
console.log(this.$refs.child instanceof Child); // false
}
}
Bind this
to some methods
The v1 had a feature that automatically bound a class method to its instance to make sure that this
was always the class instance. This feature came with a negative performance impact when working with large number of instances.
This should only have an impact on callback function use in the $on(event, callback)
method if a method was directly used as the callback:
this.$on('custom-event', this.handleCustomEvent);
To fix this, you can bind the method to this
before using it:
+ this.handleCustomEvent = this.handleCustomEvent.bind(this);
this.$on('custom-event', this.handleCustomEvent);
Or, better, you can use the EventListener.handleEvent()
method and directly use this
as the callback:
class Component extends Base {
static config = {
name: 'Component',
};
mounted() {
// The method `handleEvent` of `this` will be called
this.$on('custom-event', this);
}
destroyed() {
// Always make sure to unbind what has been binded
this.$off('custom-event', this);
}
handleEvent(event) {
if (event.type === 'custom-event') {
this.handleCustomEvent(event);
}
}
handleCustomEvent(event) {}
}
Going further
Make sure to read "DOM handleEvent: a cross-platform standard since year 2000" to learn more on how to best leverage the EventListener.handleEvent()
API.
Replace legacy config from getter to static
Using a getter for the config
was marked a legacy in the v1 and is not supported anymore in the v2.
class Component extends Base {
- get config() {
- return {
- name: 'Component',
- };
- }
+ static config = {
+ name: 'Component',
+ };
}
Replace legacy data-options
attribute
Defining custom values for an instance options with a single data-options="{}"
attribute has been marked as legacy in the v1 and is no longer supported in the v2. Custom values for options should be defined with data-option-<option-name>="value"
attributes.
<div
data-component="Component"
- data-options="{ one: 1, two: 2 }">
+ data-option-one="1"
+ data-option-two="2">
Replace get:...
event handlers
The internal get:options
, get:refs
, get:children
and get:services
events have been removed, they can be replaced with getters in child classes:
Before
class Foo extends Base {
mounted() {
this.$on('get:refs', (refs) => {
refs.body = document.body;
});
}
After
class Foo extends Base {
get $refs() {
const $refs = super.$refs;
$refs.body = document.body;
return $refs;
}
}
Define emitted events
Events emitted from a component must be defined in the static config
property.
class Component extends Base {
static config = {
name: 'Component'
+ emits: ['open', 'close'],
}
open() {
this.$emit('open');
}
close() {
this.$emit('close');
}
}