I'm trying to learn Svelte and TypeScript. I was wondering if there is any pattern to include or program svelte component using ES6 classes. Currently file contains all the script, html and data, css. I want to make them separate files. Please help me!
You can use a task runner to automate this. If you are using es6 classes I would recommend using rollup with rollup-plugin-svelte and rollup-plugin-buble.
I use Gulp to take the separate js, html and css files and concat them into a single file with the appropriate tags enclosing the script and styles. The combined file can be compiled then deleted.
Structure
To help keep the file files clean and easy to work with the HTML, CSS and JavaScript can be seperate.
src/hello/hello.css
.message {
font-size: 10pt;
}
src/hello/hello.html
<div class="message">{{message}}</div>
src/hello/hello.js
export default {
data: function () {
return {
message: 'Hello, world!'
}
}
}
Combine
Svelte requires that components be just a single html file, so the three separate files need to be combined into a single file. Since this file is HTML, the JavaScript must be wrapped in tags and the CSS must be wrapped in tags.
src/hello/hello.temp.html
<style>
.message {
font-size: 10pt;
}
</style>
<div class="message">{{message}}</div>
<script>
export default {
data: function () {
return {
message: 'Hello, world!'
}
}
}
</script>
Compile
The temp file can be compiled using svelte or rollup with the svelte plugin then deleted.
[Edit]
Here is a gist with a gulp file showing how this works.
Link here
[Edit 2]
There is a Yeoman generator to set this all up for you, here is a link to the npm package.
generator-svelte-workbench
Related
I'm not entirely sure if this is possible, but I want to dynamically load a component's template in runtime in Svelte. Basically download some user-defined template and use that to build out the component in run-time. Is this actually possible to do?
You would have to include the Svelte compiler and use that to compile the template. You could check out how the REPL's repository sets that up.
The REPL performs two major steps:
Convert the code to a raw component which still references 'svelte/internal'
Bundle the component so all referenced code is included via Rollup
The first step is easy, you just do something like this:
import { compile } from 'svelte/compiler';
const { js, css } = compile(template, {
filename: 'Component.svelte',
format: 'esm',
});
console.log(js.code, css.code);
The bundling is a bit more involved (see its worker's code). You could however, make the internals available for the import and just run the code directly.
E.g. using unpkg.com for testing and throwing the code into an iframe.srcdoc:
const code = `
${js.code.replace(
'svelte/internal',
'https://unpkg.com/svelte#3.49.0/internal/index.mjs',
)}
new Component({ target: document.body });
`;
srcdoc = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Svelte App</title>
<${''}style>${css.code}</${''}style>
</head>
<body>
<${''}script type="module">${code}</${''}script>
</body>
</html>
`;
(The tags are split using ${} because the Svelte parser will break otherwise.)
You could also insert the code directly into your document via a new module script, you just have to identify the target element somehow, e.g. by generating a unique random ID.
Here is something neat you can do to directly use the generated code: Dynamically import the script from a Blob.
const componentSrc = URL.createObjectURL(
new Blob([code], { type: 'text/javascript' })
);
const { default: Component } = await import(componentSrc);
URL.revokeObjectURL(componentSrc);
new Component({ target: ... });
If you use the component outside a sandboxed iframe, you should be aware of the XSS risk that you expose yourself to.
Hi i have a requirement for plugin store where i need to load component from core into plugins and inside plugin i need to convert that string into real component so that i can use it.
Note: better approach is most welcome in the view of plugin store inside core
my pseudo logic
get component from specified path through http
convert loaded string into real vue component and store it in a variable
render it in dom
let componentAsString =
`<template>
<div>
<h class="red">{{title}}</h>
<!--<A></A> -->
</div>
</template>
<script>
//import A from './components/A'
export default {
name: 'App',
data(){
return {
title:'Hello World'
}
},
/*components: {
A
}*/
}
</script>
<style lang="scss" scoped>
.red{color:red;}
</style>`;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
</div>
You have chosen very difficult approach to solve the requirement. Main problem is the content of the string - it is essentially a Vue SFC (.vue file). In order to turn this SFC into a Vue component usable in the browser a lot must be done. You must use Webpack (or Rollup or any other bundler), use vue-loader inside to parse the SFC and use different Webpack loaders to process each section of SFC (Babel to transpile the <scipt> block, sass-loader and sass compiler to turn <style lang="scss"> into CSS)
There are tools for doing most of this (with limitations) in the browser like for example vue3-sfc-loader but the cost is huge - vue3-sfc-loader weights around 1.4MB of minified javascript (add Vue itself or potential CSS preprocessor on top of that) and I bet performance of such solution will not be great either
Much easier approach is to use this standard tooling at build time
Just create your components as you normally do - in .vue files
Use your components as Async Components and build a "dictionary" of available components. Those components will be build at build time into separate js files and loaded into a browser on demand (when used)
// ComponentStore.js
export default {
component1: () => import('./components/component1'),
component2: () => import('./components/component2'),
}
Note: process of creating this dictionary can be automated too (inspiration)
Use the component as dynamic component
// DynamicComponent.vue
<template>
<component :is="comp" />
</template>
<script>
import ComponentStore from "ComponentStore.js"
export default {
props: ['componentName'],
computed: {
comp() {
return ComponentStore[this.componentName]
}
}
}
</script>
I want to create a page Jump to the stripe payment page use stripe-samples/firebase-subscription-payments .
so I placed it's html/css/js file(which in the "public" folder) to my nuxt app's /static.
However, since it is for static files only, so vuex and plugins could not be used. Fortunately, the tag in html reads firebase from the url, so it is possible to use firebase.
but can I put raw html/css/js files to nuxt/pages like .vue file?(I tried but couldn't..)
I know the best way is to rewrite the html/js file into vue file, but it was too difficult for me as a beginner(Also, I'm Japanese and I'm not good at English,sorry).
or can I use npm package and module in /static/files ?
I have google it for two days and couldn't resolve it.I really need help,thank you!!
here is my code:
static/public/javascript/app.js
import firebase from firebase;
/*↑ it will be error "Cannot use import statement outside a module".
but in pages/.vue files and plugins/files, it will work...
I also tried "import firebase from '~/plugins/firebase.js'"*/
const STRIPE_PUBLISHABLE_KEY = ....
static/public/index.html
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.14.6/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.6/firebase-functions.js"></script>
<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-analytics.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-firestore.js"></script>
↑ it read firebase from url, but I want use firebase module I've installed.
Eventually I rewrote the js / html code to vue. Basically it is completed just by copying the js code to mounted(), but since I could not manipulate the nested template tag with js, I rewrote a part using v-if and v-for.
There are several solutions for this.
To load 3rd party scripts, you can use the following solution: https://stackoverflow.com/a/67535277/8816585
Depending on what you're trying to load, using Nuxt plugins can also be a solution: https://nuxtjs.org/docs/2.x/directory-structure/plugins/
Lastly, here is a solution on how to properly handle Stripe in Nuxt: https://stackoverflow.com/a/67504819/8816585
But static is not a place to put your code in. As told, this is for public stuff like favicons, some free pdf book that you want to share to your visitors or alike.
Didn't use firebase with Nuxt lately but those can still probably help figuring out how to write it in Nuxt, I hope.
you can load the html by render() in your vue-component-file
nuxt.config.js
build: {
extend(config, ctx){
config.resolve.alias['vue'] = 'vue/dist/vue.common';
}
}
in your vue-component-file
<script>
import myHtml from '~/path/to/your/html/my_html.html';
export default{
render(h){
return h({
template: `<main>${myHtml}</main>`
});
}
}
</script>
and the page will be rendered as a component in your vue <router-view/> or <nuxt/>, but make sure there is no <script> tag in your my_html.html, put your js code inside the render() like below
<script>
import myHtml from '~/path/to/your/html/my_html.html';
export default{
render(h){
return h({
template: `<main>${myHtml}</main>`,
created(){
console.log('I have been created!')
},
mounted(){
console.log('I have been mounted!')
},
methods: {
exampleMethod(){
alert('this is an example')
}
}
});
}
}
</script>
In a single page app, I can do this to include a component inside a component.
$ npm install sagalbot/vue-select
<template>
<div id="myApp">
<v-select :value.sync="selected" :options="options"></v-select>
</div>
</template>
<script>
import vSelect from "vue-select"
export default {
components: {vSelect},
data() {
return {
selected: null,
options: ['foo','bar','baz']
}
}
}
</script>
How can I do this in a MPA, where I have bunch of js files or sometimes inline javascript in different pages?
I am not using any build system.
I would highly recommend using vue-cli, but if for some reason that is not possible, then I believe,though I have never tried it, you would basically need to add all your components and code into a single long js file, or include them in the right order in your html documents.
Certain component libraries can work this way, like vuetify. You simply include the whole vuetify.js file after vue.js and then you can use all the components available.
I think it would be quite a lot of work to do anything of much size, but if it is something really small you could add components in the following manner, one after another.
var componentTemplate =
`
// Template code..
`;
Vue.component('my-cool-component', {
template: componentTemplate,
data: function() {
return {
//
}
}
});
I'm using VS2015 with Gulp and I'm trying to build AngularJS with TypeScript.
In my index.html, I have a script tag to my "app.js" (the output and bundle of the TS build).
However if I want to reference my controller, and any other services - how can I avoid having to put the relevant script tags in each and every HTML file - is there a way I can just reference the app.js file and be done with it? What's the recommended approach?
Cheers,
if you want to refrence only one file in html via script tag and other files just reference in other js files then you can use requirejs. It is a nice tool to load scripts. in production it is a good approach to concat and minify all your scripts to reduce number of requests.
I managed to resolve it using experimental typescript decorators, requirejs and a little of imagination.
So, in resume I wrote two decorators one called AppStartup and other called DependsOn. So at angular bootstrap I can get and register all dependencies.
I ended up with something like it:
TodoListController.ts
import {DependsOn, AppStartup, ngControllerBase} from "../infra/core";
import {taskManagerDirective} from "../directives/TaskManagerDirective";
#AppStartup({
Name: "TodoSample"
}).Controller({
DependsOn: [taskManagerDirective]
})
export class TodoListController extends ngControllerBase {
public ByControllerAs: string;
constructor() {
super(arguments);
let $httpPromise = this.$get<ng.IHttpService>("$http");
$httpPromise.then(function ($http) {
$http.get('http://www.google.com').success(function (body) {
console.info("google.com downloaded, source code: ", body);
});
});
this.ByControllerAs = "This was included by controllerAs 'this'";
}
}
rowListItemDirective.ts
import {DependsOn, ngDirectiveBase} from "../infra/core";
import {rowListItemDirective} from "./RowListItemDirective";
#DependsOn([rowListItemDirective])
export class taskManagerDirective extends ngDirectiveBase{
public template: string = `
Parent Directive
<table>
<tbody>
<tr row-list-item-directive></tr>
</tbody>
</table>
`;
}
You can see what I did below at my github repository:
https://github.com/klaygomes/angular-typescript-jasmine-seed