kazzkiq / svelte-simple-starter-kit

ES6 + Svelte 2 + Routing + Build. Everything packed in a simple, tiny project.
14 stars 1 forks source link

example of shared component like navbar? #1

Open mspanish opened 6 years ago

mspanish commented 6 years ago

This runs great! I will be attempting to integrate a shared component myself now but thought I'd see if you already have some sample code for this. Thanks for the template!

kazzkiq commented 6 years ago

If you really aim to share components across views, you could store them as global vars (yes i'ts ugly, and its the way I did in my first projects using this template). If you're using Svelte's Store, you could "register" them there since you're already referencing your store in all your views.

But I'm honestly in doubt if the Store solution is performatic. AFAIK Store was made to handle mostly strings and one-level deep values, so while that works as a workaround, perhaps is not the best approach for many shared components.

I'm open to elegant solutions for this problem. So if you manage to work on something in your project, please share in this issue!

kazzkiq commented 6 years ago

To be more practical, here is what I did on some of my projects:

// src/main.js

import Routes from './routes';
import Topbar from './components/topbar.html';

function main () {
  window.Routes = new Routes();
  window.Topbar = new Topbar({
    target: document.body
  });
}

document.addEventListener('DOMContentLoaded', main);

This way the topbar would work independently from the routes and you could always access it via window.Topbar on other components.

But since we probably don't want to use global vars, a better approach would be:

// src/main.js

import { Store } from 'svelte/store';
import Routes from './routes';
import Topbar from './components/topbar.html';

const store = new Store({
  activeTopbarItem: 1
});

function main () {
  window.Routes = new Routes();
  window.Topbar = new Topbar({
    target: document.body,
    store
  });
}

document.addEventListener('DOMContentLoaded', main);

This way you would manage Topbar states purely from svelte/store in other components, changing it via store.set({ activeTopbarItem: ... }).

mspanish commented 6 years ago

Hello! That's pretty close to what I did - here is my main,js


import Menu from './components/Menu.html';
import { Store } from 'svelte/store.js';

import Routes from './routes';
//import 'stylific/scss/stylific';

const store = new Store({
   snippets: []
});

document.addEventListener('DOMContentLoaded', main);

function main () {
  window.Routes = new Routes();

    const nav = new Nav({
        target: document.getElementById('nav'),
        store
    })

    const menu = new Menu({
      target: document.getElementById('menu'),
      store
    })

}
window.store = store; // useful for debugging!```
mspanish commented 6 years ago

do you know how I can import whole scss projects, like a style framework? Do I do that in main.js?

mspanish commented 6 years ago

thanks again for the lovely template!

kazzkiq commented 6 years ago

Yes. I generally import my base scss file directly into main.js, pretty much like you did in yours. I also use a plugin called rollup-plugin-scss.

This plugin generates another CSS file that you can then import in your index.html

Here is a full example:

// src/main.js

import Routes from './routes';

// Importing styles like this
import './styles/base.scss';

function main () {
  window.Routes = new Routes();
}

document.addEventListener('DOMContentLoaded', main);

And in the rollup.config.js:

import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import buble from 'rollup-plugin-buble';
import uglify from 'rollup-plugin-uglify';
import scss from 'rollup-plugin-scss';

const production = !process.env.ROLLUP_WATCH;

export default {
  input: 'src/main.js',
  output: {
    sourcemap: true,
    format: 'iife',
    name: 'app',
    file: 'public/bundle.js',
  },
  plugins: [
    // Here is where the magic happens,
    // this plugin generate another css file
    // that you can import into your index.html
    scss({
      output: 'public/bundle.css',
    }),
    svelte({
      dev: !production,
      css: (css) => {
        css.write('public/components.css');
      }
    }),

    resolve(),
    commonjs(),

    production && buble({ exclude: 'node_modules/**' }),
    production && uglify(),
  ],
};
mspanish commented 6 years ago

awesome thanks! I'll post a link when my project is live :) Your implementation of roadtrip is really clean and easy to use - frankly easier for me right now than Sapper, which assumes you want a server version which I don't. Your watch for rollup works well too - although I do have to reclick the page (no live reload).

kazzkiq commented 6 years ago

Glad you liked it! This starter kit was the closest I could get to a boilerplate that doesn't get in the way when developing. Happy to see others making use of it.

Also, just in case you fall into these issues too: I've experienced some quirks on Rollup when editing SASS files imported by the main .scss file. That means that whenever you edit a sass file which is not directly imported in main.js, you will have to go to your base scss file and save it again to trigger Rollup build.

Not exactly sure why this happens, but the last time I checked, it seemed like a limitation from Rollup itself: Basically it only listens to files imported in your main JavaScript entrypoint. Any other files that are not .js get ignored and don't trigger the build action.

mspanish commented 6 years ago

thanks for the advice - reminds me of another sass watch tool I used where I always had to adjust the main scss file to trigger a rebuild. No problem there. Ah one other thing I used a hack to workaround - how about when a page needs data to already be present? I used this in the page's handler:

  get route() {
    return {
      beforeenter: function ( route ) {
        const state = store.get();
        const snippets = state.snippets;
        if (snippets.length < 1) {
          return wait( 500 );
        }
      },
mspanish commented 6 years ago

hey i have another issue with routing - when you navigate from the nav - which looks like this

nav

if you do this from the index - all is great - you get the route. If you are already IN the route, then you get the wrong url , for example

http://localhost:5100/topics/topics/map_filter_reduce

I've tried with and without the './' in front of the route

kazzkiq commented 6 years ago

I generally use absolute paths, like that:

/topics/{cat.id}

Instead of:

./topics/{cat.id}

or

topics/{cat.id}

If you're interested, I also wrote a super simple component to handle links via roadtrip.goto(), so you don't have to trigger full page reloads everytime you click a link. You can check it here.

The usage is like that:

<Link href="/path/to/my/route" cssClass="optional-css-classes">Blabla</Link>
mspanish commented 6 years ago

muito obrigado Claudio 👍 faz muito tempo que nao falo, mais sei un pouco de Portugues!

kazzkiq commented 6 years ago

De nada, Stacey! Fico feliz em poder ajudar. 😄