How to separate bundles in StencilJS for third-party libraries - javascript

I am going to use third-party web components library in a Stencil project.
But when I do this, all dependent code are included into bundle with my stencil component and is a big size.
How to separate third-party components/modules code in stencil build?
import { Component, h } from '#stencil/core';
import { ModuleManager } from 'igniteui-webcomponents-core';
import { IgcDataGridModule } from 'igniteui-webcomponents-grids';
import { IgcDataGridComponent } from 'igniteui-webcomponents-grids';
#Component({
tag: 'test-component',
styleUrl: 'test-component.css',
shadow: true,
})
export class TestComponent {
data: Array<Object>;
grid: IgcDataGridComponent;
constructor() {
ModuleManager.register(
IgcDataGridModule
);
}
componentDidRender() {
this.grid.dataSource = this.data;
}
render() {
...
return (
<div>Test component
<igc-data-grid ref={el => this.grid = el as IgcDataGridComponent}
height="100%"
width="100%"
auto-generate-columns="true"
default-column-min-width="100"
summary-scope="Root"
is-column-options-enabled="true"
is-group-collapsable="true"
group-header-display-mode="Combined"
group-summary-display-mode="RowBottom"
column-moving-mode="Deferred"
column-moving-animation-mode="SlideOver"
column-moving-separator-width="2"
column-showing-animation-mode="slideFromRightAndFadeIn"
column-hiding-animation-mode="slideToRightAndFadeOut"
selection-mode="SingleRow"
corner-radius-top-left="0"
corner-radius-top-right="0">
</igc-data-grid>
</div>
);
}
}
For example, in this code I need igc-data-grid component will be bundled into separate file. Also igniteui-webcomponents-core, igniteui-webcomponents-grids modules needs to be in separate files to be used in, probably, other stencil components.

Related

JSONForms Vue Basic String Custom Renderer

So I'm starting out with Vue JSONForms and I'm trying to create a bare-bones custom text renderer. I know there JSONForms has the vue-vanilla package, but I want to understand what are the basics needed for a custom renderer because later on I will need to do much more customization to each custom renderer I create. Here is what I have so far:
<template>
<v-input />
</template>
<script lang="ts">
import { ControlElement, JsonFormsRendererRegistryEntry, rankWith, isStringControl } from '#jsonforms/core'
import { useJsonFormsControl, RendererProps } from '#jsonforms/vue'
import { defineComponent } from 'vue'
const renderersText = defineComponent({
name: 'renderers-text',
setup (props: RendererProps<ControlElement>) {
return useJsonFormsControl(props)
},
})
export default renderersText
export const entry: JsonFormsRendererRegistryEntry = {
renderer: renderersText,
tester: rankWith(1, isStringControl),
}
</script>
But I'm getting a r.tester is not a function error. Any idea what this means and/or what I need to fix? Thanks in advance!

Writing documentation for plain JS class in storybook

I have just started using Storybook for a UI component lib I am working on. I wanted to extract JSDoc written for JS class methods and properties into Storybook and create a Doc.
Storybook does support creating doc for React components by reading its propTypes. Is there addon or someway to do the same for a JS class.
I am using the latest storybook 6.
Thanks in advance
You can do it like a normal component:
form-validators.stories.ts
import { FormValidators } from './path';
export default {
title: 'Components/Form Validators',
component: FormValidators,
parameters: {
previewTabs: { canvas: { hidden: true } },
docsOnly: true,
},
} as Meta;
export const Default: Story = () => ({
template: '<div>Test</div>',
});
Or I prefer an MDX file.
form-validators.stories.mdx
import { ArgsTable } from '#storybook/addon-docs/blocks';
import { Meta } from '#storybook/addon-docs/blocks';
import { FormValidators } from './path';
<Meta
title="Components/Form Validators"
parameters={{ previewTabs: { canvas: { hidden: true } } }}
/>
<ArgsTable of={FormValidators} />

How do I create a function library which I can used across all my Vuejs components?

I currently writing a financial application using Vue.js and Vuetify. I have a few component files and javascript files like
Dashboard.vue
Cashflow.vue
NetWorth.vue
stores.js <- Vue Vuex
I have some functions which I need to use across all the Vue.js and javascript files. Would it be possible for me to perhaps write a function library which can be used across all
the component and js files.
function moneyFormat(num)
function IRRCalc(Cashflow)
function TimeValueMoneyCalc(I,N,PV,FV,PMT)
function PerpetualAnnuityCalc(I,PV)
function CarLoanInstallment(V,N)
function HouseLoanInstallment(V,N)
I know in C it is very simple just #include<financial.h> was wondering is there something similar in javascript.
Thanks.
There are 3 ways to do this:
1/You can create a helper.js file and import it to .vue files
// helper.js
export default {
function moneyFormat(num) { // some logic}
}
// Dashboard.vue
<script>
import helper from "helper.js" //the path may change depends on where you put the js file
methods: {
useHelper(value) {
helper.moneyFormat(value)
}
}
</script>
2/Another way is bind the function to Vue prototype
in main.js
Vue.prototype.$moneyFormat= function moneyFormat(num) {}
then in Dashboard.vue just call this.$moneyFormat(num). No need to import anything
3/ Use mixins. You can search online on how to use this https://v2.vuejs.org/v2/guide/mixins.html
You can create a single JS file that holds all the helper/util methods, and then export them individually:
export function moneyFormat(num) { ... }
export function IRRCalc(Cashflow) { ... }
export function TimeValueMoneyCalc(I,N,PV,FV,PMT) { ... }
export function PerpetualAnnuityCalc(I,PV) { ... }
export function CarLoanInstallment(V,N) { ... }
export function HouseLoanInstallment(V,N) { ... }
Then, you can simply import individual methods as of when needed, i.e.:
import { CarLoanInstallment, HouseLoanInstallment } from '/path/to/helper/file';
This can be quite usefuly for tree-shaking when you're bundling with webpack, for example, so that you don't bundle unnecessary functions that are never used in your project.
You can use Mixin
In your main.js, add Vue.mixin:
import Vue from "vue";
import App from "./App.vue";
Vue.mixin({
methods: {
helloWorld() {
alert("Hello world");
}
}
});
new Vue({
render: h => h(App)
}).$mount("#app");
and then you can call helloWorld() method from your component script with this.helloWorld() or just helloWorld() from the template.
You also can use filters if the method is to apply common text formatting
In your main.js, add Vue.filter:
import Vue from "vue";
import App from "./App.vue";
Vue.filter("capitalize", function(value) {
if (!value) return "";
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});
new Vue({
render: h => h(App)
}).$mount("#app");
and then you can do {{ "some text" | capitalize }} to apply capitalize filter on "some text"
Example here: https://codesandbox.io/s/heuristic-dirac-esb45?file=/src/main.js:0-226

Multiple imported and registered components in vue.js

I am refactoring some code in my app and turns out,the below logic it is repeated in many many components.
import component1 from '...'
import component2 from '...'
import component3 from '...'
//...many others
export default {
//other data
components: {
component1,
component2,
component3
//...
}
}
Does exists a shorter approach in order to clean my code?
Thanks for your time
Below are 3 ways.I prefer method 3 by the way.
Method 1
Create a js file in my case dynamic_imports.js:
export default function (config) {
let registered_components = {}
for (let component of config.components) {
registered_components[component.name] = () => System.import(`../${config.path}/${component.file_name}.vue`)
}
return registered_components
}
In the component in which you have many component imports and registrations
import dynamic_import from '#/services/dynamic_imports' //importing the above file
let components = dynamic_import({
path: 'components/servers',
components: [
{ name: 'server-one', file_name: 'serverOne' },
{ name: 'server-two', file_name: 'serverTwo' },
]
})
export default {
//...other code
components: components
}
As a result you will import and register your components with "clean code".
But note that this worked for me,maybe it has to modified a lit bit to fit your needs,to understand:
The property path means that will look at this path for the names specified in file_name.The name property is the name you register the component
Method 2
If you don't like the above look below to another way:
function import_component(cmp_name){
return System.import(`#/components/${cmp_name}.vue`);
}
export default{
components: {
'component1': () => import_component('componentOne'),
'component2': () => import_component('componentTwo'),
'component3': () => import_component('componentThree')
}
}
Method 3
If again you are saying: This is not a cleaner way,take a look below but keep in mind that if you are working in team and skills differ,then some programmers will be a little bit confused.
dynamic_imports.js
export default function ({path, file_names, component_names}) {
let registered_components = {}
for (let [index, file_name] of file_names.entries()) {
registered_components[component_names[index]] = () => System.import(`../${path}/${file_name}.vue`)
}
return registered_components
}
In your component
import dynamic_import from '#/services/dynamic_imports'
let components = dynamic_import({
path: 'components/servers',
file_names: ['serverOne', 'serverTwo'],
component_names: ['server-one', 'server-two']
})
export default {
components: components
}
You can automatically register such repeated base components globally using the pattern described in the official docs
https://v2.vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components
Chris Fritz also talks about this pattern in his awesome video where he mentions 7 secret patterns for cleaner code and productivity boost while working with Vue.js
The disadvantage of this approach, however, is that the components that you autoregister this way always end up in the main bundle and therefore cannot be lazy loaded/code-splitted. So make sure you do this only for the base components that are very generic.

Typescript import from .d.ts file

I wrote a (at this point) simple components for angular2.
Here's my code so far:
import {Component, View} from 'angular2/angular2';
export module SkApp.Core{
#Component({
selector: 'sk-app-side-menu'
})
#View({
template: `
<p>Hello</p>
`
})
export class SkAppSideMenu {
menuActive: boolean;
constructor(){
this.menuActive = false;
}
showMenu(){
this.menuActive = !this.menuActive;
}
}
}
Of course there's no real functionality at this point. But that's not the point right now.
I also created my own build process with gulp. Here's the relevant part of it:
gulp.task('script', ['clean'], function() {
var tsResult = tsProject.src()
.pipe(ts(tsProject));
return merge([
tsResult.dts.pipe(rename({dirname: ''}))
.pipe(concat('sk-app.d.ts'))
.pipe(gulp.dest('dist/')),
tsResult.js
.pipe(rename({dirname: ''}))
.pipe(concat('sk-app.min.js'))
.pipe(uglify())
.pipe(gulp.dest('dist/'))
]);
});
At the end I get two files: sk-app.min.js and sk-app.d.ts
sk-app.min.js:
var __decorate=this&&this.__decorate||function(t,e,n,r){if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)return Reflect.decorate(t,e,n,r);switch(arguments.length){case 2:return t.reduceRight(function(t,e){return e&&e(t)||t},e);case 3:return t.reduceRight(function(t,r){return void(r&&r(e,n))},void 0);case 4:return t.reduceRight(function(t,r){return r&&r(e,n,t)||t},r)}},__metadata=this&&this.__metadata||function(t,e){return"object"==typeof Reflect&&"function"==typeof Reflect.metadata?Reflect.metadata(t,e):void 0},angular2_1=require("angular2/angular2"),SkApp;!function(t){var e;!function(t){var e=function(){function t(){}return t.prototype.showMenu=function(t){},t=__decorate([angular2_1.Component({selector:"sk-app"}),angular2_1.View({template:'\n <button (click)="showMenu()">click me!</button>\n\n <ng-content></ng-content>\n ',directives:[angular2_1.NgClass]}),__metadata("design:paramtypes",[])],t)}();t.SkApp=e}(e=t.Core||(t.Core={}))}(SkApp=exports.SkApp||(exports.SkApp={}));
sk-app.d.ts:
export declare module SkApp.Core {
class SkApp {
showMenu(x: string): void;
}
}
Now I want to use this component within another angular2 project:
import {Component, View, bootstrap} from 'angular2/angular2';
import {SkApp} from "SkApp/Core";
#Component({
selector: 'my-app'
})
#View({
template: '<sk-app></sk-app>',
directives: [SkApp]
})
class MyAppComponent {
}
bootstrap(MyAppComponent);
But when I try to compile this project to js the typescript compiler gives me this message:
error TS2307: Cannot find module 'SkApp/Core'
When I change the module-definition within my sk-app.d.ts file to:
declare module "SkApp/Core" {
it works fine. But I want to have my definition files to be generated by gulp without having to change the module declaration myself.
Any help with this would be appreciated.
(Of course I am aware, that angular2 is still in alpha state)
export module SkApp.Core{
I think it should be:
module SkApp.Core {...
Since for what I know, Typescript doesn't have module level visibility modifiers

Categories