Comment on page
Migrating to 3.0
matestack-ui-core
previously contained logic for- Ruby -> HTML conversion
- Reactivity via prebuilt and custom Vue.js components
- In order to have better seperation of concerns, we've moved the reactivity related things to its own repository/gem ->
matestack-ui-vuejs
matestack-ui-core
is now meant to be combined with any reactivity framework or none at all
If you've used reactivity features of
matestack-ui-core
2.x you now have to install matestack-ui-vuejs
(Ruby Gem & NPM Package) additionally:Gemfile
gem 'matestack-ui-core', '~> 3.0.0'
gem 'matestack-ui-vuejs', '~> 3.1.0'
matestack-ui-core
does not ship a JavaScript package anymore- please remove the package from your application and switch to
matestack-ui-vuejs
for the VueJs driven reactivity if required
yarn remove matestack-ui-core
- and add
matestack-ui-vuejs
:
package.json
{
"name": "my-app",
"dependencies": {
"matestack-ui-vuejs": "^3.1.0", // <-- new package name
"..."
}
}
- vue3 dropped IE 11 support
- when using babel alongside webpacker, please adjust your
package.json
or.browserslistrc
config in order to exclude IE 11 support:
{
"name": "my-app",
"...": { },
"browserslist": [
"defaults",
"not IE 11" // <-- important!
]
}
Otherwise you may encounter issues around
regeneratorRuntime
(especially when using Vuex)config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require('webpack');
const customWebpackConfig = {
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler',
'matestack-ui-vuejs': 'matestack-ui-vuejs/lib/matestack/ui/vue_js/index.js' // in order not to use the esm package
}
},
plugins: [
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false
})
]
}
environment.config.merge(customWebpackConfig)
module.exports = environment
Don't forget to restart webpacker when changing this file!
and then just use
import { whatever } from 'vue'
instead of import { whatever } from 'vue/dist/vue.esm'
Optional: vue3 compat build usage
If you, or any of the libraries you're using, are consuming any vue2 APIs, you can use the vue3 compat build. This enables you to use both vue2 and vue3 APIs and migrate step by step.
Usage via webpack config when using webpacker 5.x and up:
config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
const customWebpackConfig = {
resolve: {
alias: {
vue: '@vue/compat/dist/vue.esm-bundler',
'matestack-ui-vuejs': 'matestack-ui-vuejs/lib/matestack/ui/vue_js/index.js' // in order not to use the esm package
}
},
plugins: [
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false
})
]
}
environment.config.merge(customWebpackConfig)
module.exports = environment
Matestack::Ui::App
was always meant to be a layout wrapping pages, but was supercharged with some vuejs logic before splitting the core
and vuejs
repos. Now Matestack::Ui::App
is only a layout, that's why it should be named like that: Matestack::Ui::Layout
Protip: Search & Replace
Following the above mentioned naming adjustment, the
matestack_app
method used on controller level is renamed to matestack_layout
app/controllers/demo_controller.rb
class DemoController < ActionController::Base
include Matestack::Ui::Core::Helper
layout "application" # root rails layout file
# matestack_app DemoApp::Layout
matestack_layout DemoApp::Layout # <-- renamed from matestack_app
def foo
render DemoApp::Pages::Foo
end
end
Previously,
Matestack::Ui::App
added some wrapping DOM structures around the whole layout and around it's yield
. This enabled dynamic page transition and loading state animations.Matestack::Ui::Layout
now purely renders the layout and yields a page without anything in between. The wrapping DOM structures required for dynamic page transitions and loading state animations needs to be added via two new components if you want to use these features via matestack-ui-vuejs
(see section below!)matestack/some/app/layout.rb
class Some::App::Layout < Matestack::Ui::Layout
def response
h1 "Demo App"
main do
yield
end
end
end
matestack/some/app/pages/some_page.rb
class Some::App::Pages::SomePage < Matestack::Ui::Page
def response
h2 "Some Page"
end
end
will just render:
<body> <!-- coming from rails layout if specified -->
<!-- no wrapping DOM structure around the layout -->
<h1>Demo App</<h1>
<main>
<!-- page markup without any wrapping DOM structure -->
<h2>Some Page</h2>
<main>
</body>
As seen in the above example,
Matestack::Ui::Layout
classes are no longer automatically wrapped by a component tag meant to mount the matestack-ui-core-app component on it.This has to be done manually via the
matestack_vue_js_app
component, which is more explicit and provides more flexibility. Additionally, the page_switch
component has to wrap the yield
in order to support dynamic page transitions:matestack/some/vue_js/app/layout.rb
class Some::VueJs::App::Layout < Matestack::Ui::Layout
def response
h1 "Demo VueJs App"
matestack_vue_js_app do # <-- this one
main do
page_switch do # <-- and this one
yield
end
end
end
end
end
Using these components will add the original wrapping DOM structures which enables loading state animations.
The new
<matestack-component-template>
will be rendered coming from these two new components<body> <!-- coming from rails layout if specified -->
<div id="matestack-ui"> <!-- coming from rails layout if specified -->
<h1>Demo VueJs App</h1>
<matestack-component-template> <!-- new tag rendered since 3.0, should not break anything -->
<div class="matestack-app-wrapper">
<main>
<matestack-component-template> <!-- new tag rendered since 3.0, should not break anything -->
<div class="matestack-page-container">
<div class="matestack-page-wrapper">
<div> <!--this div is necessary for conditonal switch to async template via v-if -->
<div class="matestack-page-root">
your page markup
</div>
</div>
</div>
</div>
</matestack-component-template>
</main>
</div>
</matestack-component-template>
</div>
</body>
Following the repo/gem split, the Vue.js related libary is now called
MatestackUiVueJs
// import MatestackUiCore from 'matestack-ui-core'
import MatestackUiVueJs from 'matestack-ui-vuejs' // Replace import statement
// MatestackUiCore.eventHub.$emit('some-event')
MatestackUiVueJs.eventHub.$emit('some-event') // -> Replace references
Protip: Search & Replace
javascript/packs/application.js
import { createApp } from 'vue'
import MatestackUiVueJs from 'matestack-ui-vuejs'
const appInstance = createApp({})
document.addEventListener('DOMContentLoaded', () => {
MatestackUiVueJs.mount(appInstance) // use this mount method
})
some/component/file.js
import MatestackUiVueJs from 'matestack-ui-vuejs'
const myComponent = {
mixins: [MatestackUiVueJs.componentMixin],
template: MatestackUiVueJs.componentHelpers.inlineTemplate,
data() {
return {
foo: "bar"
};
},
mounted(){
console.log("custom component mounted")
}
};
export default myComponent
javascript/packs/application.js
import { createApp } from 'vue'
import MatestackUiVueJs from 'matestack-ui-vuejs'
import myComponent from 'some/component/file.js' // import component definition from source
const appInstance = createApp({})
appInstance.component('my-component', myComponent) // register at appInstance
document.addEventListener('DOMContentLoaded', () => {
MatestackUiVueJs.mount(appInstance)
})
- For application components, apply
template: MatestackUiVueJs.componentHelpers.inlineTemplate
some/component/file.js
import MatestackUiVueJs from 'matestack-ui-vuejs'
const myComponent = {
mixins: [MatestackUiVueJs.componentMixin],
template: MatestackUiVueJs.componentHelpers.inlineTemplate, // this one!
data() {
return {
foo: "bar"
};
},
mounted(){
console.log("custom component mounted")
}
};
export default myComponent
- Only for core components
- add import
import componentHelpers from 'some/relative/path/to/helpers'
- and then apply
template: componentHelpers.inlineTemplate
Use
vc.
(short for vue component) in order to prefix all- Properties
- References
- Or method calls
within your vue.js component
response
.some/component/file.js
import MatestackUiVueJs from 'matestack-ui-vuejs'
const myComponent = {
mixins: [MatestackUiVueJs.componentMixin],
template: MatestackUiVueJs.componentHelpers.inlineTemplate,
data() {
return {
foo: "bar"
};
},
mounted(){
console.log(this.foo) // --> bar
// or:
console.log(vc.foo) // --> bar
}
};
export default myComponent
class Components::MyComponent < Matestack::Ui::VueJsComponent
vue_name "my-component"
def response
div do
plain "{{foo}}" # --> undefined!
plain "{{vc.foo}}" # --> bar
end
end
end
- use
this.getRefs()
instead ofthis.$refs
- use
matestack_ui_vuejs_ref()
when applying refs to your component template:
def response
# ...
div ref: "some-ref" # <-- not picked up by this.getRefs()
# ...
div "matestack-ui-vuejs-ref": matestack_ui_vuejs_ref('some-ref')
end
Use
this.getElement()
instead of this.$el
in order to get the root element defined in your response
method.Protip: Search & Replace
Additional Note:
Use
this.getTemplateElement()
in order to get the template element (matestack-component-template
tag) wrapping the root element defined in your response
method.beforeDestroy
was renamed to beforeUnmount
within vue3.Protip: Search & Replace
destroyed
was renamed to unmounted
within vue3.Protip: Search & Replace
this.$set
and Vue.set
are removed in vue3 as they are no longer required for proper reactivity binding. If you use these methods, use plain JavaScript mutations instead.Previously a Vuex store was required and by default available. Now it's optional
You can add a store manually following the official Vuex 4.x docs
Last modified 1yr ago