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.rc2'
gem 'matestack-ui-vuejs', '~> 3.0.0.rc3'
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.0.0-rc3", // <-- 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',
}
},
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're using any vue2 APIs (or one of the libraries you're using), 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',
}
},
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 thecore
andvuejs
repos- now
Matestack::Ui::App
is only a layout, that's why it should be named like that:Matestack::Ui::Layout
-> Search&Replace
- following the above mentioned naming adjustment, the
matestack_app
method used on controller level is renamed tomatestack_layout
app/controllers/demo_controller.rb
class DemoController < ActionController::Base
include Matestack::Ui::Core::Helper
layout "application" # root rails layout file
matestack_layout DemoApp::Layout # <-- renamed from matestack_app
def foo
render DemoApp::Pages::Foo
end
end
- previously,
Matestack::Ui::App
added some wrapping DOM structure around the whole layout and around it'syield
- 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 structres 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 DON structure around the layout -->
<h1>Demo App</<h1>
<main>
<!-- page markup without any wrapping DOM structure -->
<h2>Some Page</h2>
<main>
</body>
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 gives more flexibility - additionally, the
page_switch
component has to wrap theyield
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 structres which enables loading state animations
- new
<matestack-component-tempate>
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-tempate> <!-- new tag rendered since 3.0, should not break anything -->
<div class="matestack-app-wrapper">
<main>
<matestack-component-tempate> <!-- 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-tempate>
</main>
</div>
</matestack-component-tempate>
</div>
</body>
- following the repo/gem split, the Vue.js related libary is now called
MatestackUiVueJs
-> 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
- add import
- use
vc.
(short for vue component) in order to prefix all properties references or method calls within your vue.js componentresponse
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 componen 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 ofthis.$el
in order to get the root element defined in yourresponse
method
-> Search&Replace
Additional Note:
- use
this.getTemplateElement()
in order to get the template element (matestack-component-template
tag) wrapping the root element defined in yourresponse
method
beforeDestroy
was renamed tobeforeUnmount
within vue3
-> Search&Replace
this.$set
andVue.set
are removed in vue3 as they are not 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