Import leaflet in single component svelte - javascript

I'm using in a single component leaflets plugin, for the moment I put the js and css in public/index.html but i need to find a way to import only the js and css in the single component. Also i tryed with svelte::head but it didn't work. Also this project is going to be used like a node_modules, so i need to find a way to not put the js and css files in folder public. Any suggestions? I tryed to import leaflet installing leaflet with npm and import like
import from 'leaflet'
import * as L from 'leaflet'
but it didn't work.

You can import the styles using rollup-plugin-css-only. To avoid the ugly css import with a relative path to node_modules you may want to use postcss instead: https://medium.com/#bekzatsmov/how-to-import-css-from-node-modules-in-svelte-app-2a38b50924ff
This is based on the standard Svelte template: https://github.com/sveltejs/template
App.svelte
<script>
import * as L from 'leaflet';
import '../node_modules/leaflet/dist/leaflet.css'; // It might be better to use postcss.
import { onMount } from 'svelte';
let div = null;
onMount(() => {
let map = L.map(div, {
center: [17.385044, 78.486671],
zoom: 10
});
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
});
</script>
<div bind:this={div} style="height: 100vh; width: 100%;"></div>
main.js
import App from './App.svelte';
const app = new App({
target: document.body
});
rollup.config.js
import svelte from 'rollup-plugin-svelte';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file - better for performance
css: false,
emitCss: true
}),
css({ output: 'public/build/bundle.css' }),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
function serve() {
let started = false;
return {
writeBundle() {
if (!started) {
started = true;
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
}
}
};
}
export default app;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel='stylesheet' href='/global.css'>
<link rel='stylesheet' href='/build/bundle.css'>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>

Related

How to tell Vite to exclude a subset of files in a directory from build?

I created a new Vue app using npm create vue. During runtime this app fetches a configuration and reads a string from it. This string represents the name of a component to render inside the app. Those dynamic components live inside a "pluggable" directory
.
└── src
├── App.vue
└── pluggables
├── ThisFoo.vue
└── ThatBar.vue
So basically what the App.vue file does is
<script setup lang="ts">
import { onMounted, shallowRef, defineAsyncComponent } from "vue";
const pluggableComponent = shallowRef();
onMounted(() => {
// fetch configuration
const componentName = "ThisFoo"; // extract from configuration
pluggableComponent.value = defineAsyncComponent(() => import(`./pluggables/${componentName}.vue`));
});
</script>
<template>
<div>Pluggable below:</div>
<component :is="pluggableComponent" />
</template>
I have access to the configuration file during build time and know which components I need during runtime and which ones to consider as "dead code" based on this configuration. Is there a way to tell Vite to exclude the unused components from the build?
E.g. exclude the whole pluggables directory but include the required components from the pluggables directory
vite build --exclude ./src/pluggables/** --include ./src/pluggables/ThisFoo.vue
or by creating a custom Vite build function I can call during CI/CD and pass in an array of component names.
To exclude some files from the build process you can mark them as external files by using the external config of Rollup
// vite.config.js
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import * as path from "path";
import { fileURLToPath } from "node:url";
const filesNeedToExclude = ["src/pluggables/Comp1.vue", "src/pluggables/Comp2.vue"];
const filesPathToExclude = filesNeedToExclude.map((src) => {
return fileURLToPath(new URL(src, import.meta.url));
});
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"#": path.resolve(__dirname, "./src"),
},
},
build: {
manifest: true,
rollupOptions: {
external: [
...filesPathToExclude
],
},
},
});
Based on Duannx answer I came up with the following solution to exclude everything in the directory except the desired components
import { readdirSync } from 'node:fs'
import { join } from 'node:path'
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
function getPluggablesToExclude(): string[] {
const rawPluggablesToInclude = process.env.PLUGGABLES; // !! set this env variable in the CI pipeline !!
if (!rawPluggablesToInclude) { // if missing, exclude nothing
return [];
}
const pluggablesToInclude = rawPluggablesToInclude.split(',').map(component => `${component}.vue`);
const pluggablesDirectoryPath = join(__dirname, 'src', 'pluggables');
const filesInPluggablesDirectory = readdirSync(pluggablesDirectoryPath);
const filesToExclude = filesInPluggablesDirectory.filter(file => !pluggablesToInclude.includes(file));
return filesToExclude.map(file => join(pluggablesDirectoryPath, file));
}
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
external: [
...getPluggablesToExclude()
],
},
},
})
So all I have to do is to set the env variable in my CI pipeline. If I skip this step, the build will include every component.

How to configure runtime compilation in Vue and Snowpack

I'm trying to get a Vue project setup with runtime compilation, but I'm not quite sure how to configure this in Snowpack.
Basically currently when I run the project I get a blank screen and the usual "[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".
Currently my files look like below:
snowpack.config.js:
/** #type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
public: '/',
src: '/_dist_',
},
plugins: [
'#snowpack/plugin-vue',
'#snowpack/plugin-dotenv'
],
...
}
index.js:
import { createApp } from "vue";
// import App from "./App.vue";
import First from "./First.vue";
// const app = createApp(App);
const app = createApp({
data() {
return {
message: 'duck',
}
}
});
app.component('first', First);
app.component('ducks', {
props: ['todo'],
template: '<li>{{ todo }}</li>'
});
app.mount("#app");
// Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
// Learn more: https://www.snowpack.dev/#hot-module-replacement
if (import.meta.hot) {
import.meta.hot.accept();
import.meta.hot.dispose(() => {
app.unmount();
});
}
index.html:
...
<body>
<div id="app">
<p>stuff should be fine:</p>
<p>{{message}}</p>
<ul>
<li>hello</li>
<ducks todo="testing"></ducks>
<ducks todo="goats"></ducks>
<ducks todo="canoes"></ducks>
</ul>
</div>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script type="module" src="/_dist_/index.js"></script>
</body>
...
I've tried adding an alias but that doesn't seem to do anything:
snowpack.config.js
module.exports = {
...
plugins: [
'#snowpack/plugin-vue',
'#snowpack/plugin-dotenv'
]
...
alias: {
'vue': 'vue/dist/vue.esm-bundler.js'
}
Anybody know how I can get runtime compilation setup?
Thanks,
Matt
I managed to fix this, by using import { createApp, h } from "vue/dist/vue.cjs.prod.js";.
But I'm not sure if this will create other issues in the future.

Include pictures in JS bundle

My case is the following :
I create a components library for React. So I have a package (bundled with Rollup) that include some pictures (For now only a GIF picture that is used in a component).
The component that use my picture is like this :
import React from 'react';
import PropTypes from 'prop-types';
import ui_spinner from '../../../assets/ui_progress.gif';
/**
* CircularSpinner
* Add a spinner when the user needs to wait
*/
class CircularSpinner extends React.PureComponent {
static propTypes = {
/** Width of the component */
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** Height of the component */
height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** Style of the component (overload existing properties) */
style: PropTypes.object,
}
static defaultProps = {
width: 128,
height: 128,
style: {},
}
render() {
const { style, width, height } = this.props;
return (
<img src={ui_spinner} width={width} height={height} style={style} alt="ui_progress" aria-busy="true" />
);
}
}
export default CircularSpinner;
When I built it, it's OK.
Now I create a React application with create-react-app and I want to test my components library. To do this, I use npm link (To avoid to push deploy my npm package). My components are OK in my testing application but the picture (the GIF in my CircularSpinner component) is not displayed.
So my question is the following : How to include some assets in a JS bundle with Rollup ? My working approach is correct ?
My Rollup config is the following :
import { uglify } from 'rollup-plugin-uglify'
import babel from 'rollup-plugin-babel'
import url from 'rollup-plugin-url'
const config = {
input: 'src/index.js',
external: ['react'],
output: {
format: 'umd',
name: 'react-components',
globals: {
react: "React"
}
},
plugins: [
babel({
exclude: "node_modules/**"
}),
uglify(),
url(),
]
}
export default config
I build with rollup -c -o dist/index.js.
And the dist folder has the following content :
dist/
assets
92be5c546b4adf43.gif
index.js
My component that use my picture is like this in my testing application :
<img src="92be5c546b4adf43.gif" width="128" height="128" alt="ui_progress" aria-busy="true">
Thanks for your help !
Damien
I found the solution for this issue. This response may help someone :
I update my rollup config to use rollup-plugin-img. I have already used it but my configuration was not correct :
The correct config is the following :
import { uglify } from 'rollup-plugin-uglify'
import babel from 'rollup-plugin-babel'
import image from 'rollup-plugin-img'
const config = {
input: 'src/index.js',
external: ['react'],
output: {
format: 'umd',
name: 'react-components',
globals: {
react: "React"
}
},
plugins: [
babel({
exclude: "node_modules/**"
}),
image({
limit: 100000,
}),
uglify(),
]
}
export default config
My error was that my GIF is a little big and the default limit size is 8192 bytes.
In this case, I have the following error :
Error: Could not load <path of image> (imported by <path of component that use image>): The "path" argument must be of type string. Received type undefined
When I have updated my config to increase the limit, everything is OK

Do I need to (or should I) wrap all my Vue components in a wrapper component?

I am trying to put together Webpack 4.5 and Vue components. The build is fine and I see on the screen the expected two components (details below).
Creating this basic SPA was a very iterative process, with information gathered from various sources (not always consistent). I finally end up with:
an HTML file which has one Vue component, a wrapper for the whole SPA
the Vue component above, which itself brings in the actual useful components
Is there a way to skip the wrapper component so that I can directly edit the HTML file (and link a CSS style file)? I would then define a CSS grid and place the components within.
Or is there an advantage to keep it this way I do not foresee?
The current project files:
the HTML file opened in the browser
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<infoscreen id="infoscreen"></infoscreen>
</body>
<script src="bundle.js"></script>
</html>
the webpack config file
'use strict'
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
mode: 'development',
entry: [
'./src/entry.js'
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
new CopyWebpackPlugin([{
from: 'src/infoscreen.html',
to: 'infoscreen.html'
}])
]
}
the entry.js file
import infoscreen from "./infoscreen.vue"
import Vue from "vue/dist/vue.js"
Vue.component("infoscreen", infoscreen)
new Vue({ el: "infoscreen" })
the Vue wrapper component (infoscreen.vue)
This is the file I would like to get rid of and use <temperature-outside></temperature-outside> directly in the HTML file above
<template>
<div id="app">
<temperature-outside></temperature-outside>
<temperature-outside></temperature-outside>
</div>
</template>
<script>
import temperatureOutside from './temperatureOutside.vue'
export default {
name: 'infoscreen',
components: {
'temperature-outside': temperatureOutside
}
}
</script>
the Vue component (temperatureOutside.vue)
<template>
<div>
hello {{yo}}
</div>
</template>
<script>
export default {
name: 'temperatureOutside',
data: function () {
return {
yo: "world"
}
}
}
</script>
Vue components are recognized within the context of a Vue instance. It turns out you will need a mounting point in your html which the wrapping or parent Vue component will mount all child components registered.
Registering Components

How to use external html templates in Components with Vue.js 2.0 in Laravel 5.3

I am using the default Laravel 5.3 setup - a fresh install with default configuration for Vue.js 2.0.
With Laravel 5.1 and Vue.js 1.x, I could easily define components like and used browserify to compile.
Vue.component('test-component', require('./test-component');
/* test-component.js */
export default{
template:require('./test-component.template.html')
}
/* test-component.template.html */
<div class="test-component">
<h1> Test Component <h1>
</div>
However, with Vue 2, the default is webpack (although browserify is also available but could not get it working and webpack seems better). But I am not able to get the configuration working.
I have tried various configurations, finally I have this in my gulp.js file
const elixir = require('laravel-elixir');
require('laravel-elixir-vue-2');
var config = {
module:{
loaders:[
{
test: /\.html$/,
loader: 'vue-loader'
}
]
}
};
elixir(mix => {
mix.sass('app.scss')
.webpack('app.js',null, null, config);
});
Now I am not getting any errors while compiling gulp webpack however when I try to view the page in the browser, it doesn't show the component and has an error/warn in the console
vue.js?3de6:513[Vue warn]: invalid template option:[object Object]
(found in component <test>)
vue.js?3de6:4085Uncaught TypeError: Cannot read property 'child' of null(…)
My app.js main entry file (default provided by Laravel)
require('./bootstrap');
Vue.component('test-component', require('./components/test-component'));
const app = new Vue({
//el: '#app',
}).$mount('#app');
What am I missing? Any pointers would be appreciated.
You have to use html-loader instead of vue-loader.
npm install html-loader --save-dev
Your gulpfile.js (need to change the loader):
const config = {
module: {
loaders:[{
test: /\.html$/,
loader: 'html'
}]
}
};
elixir((mix) => {
mix.sass('app.scss')
.webpack('app.js', null, null, config);
});
Your test-component.js (no changes, you're good to go):
export default {
template: require('./test-component.template.html')
}
Your test-component-template.html: (no changes, you're good to go)
<div class="test-component">
<h1>Test Component Goes Here</h1>
</div>
Important
Here's how to define your component:
Using Default
Vue.component('test-component', require('./test-component').default);
Or, simply use ES2015 import
import TestComponent from './test-component';
Vue.component('test-component', TestComponent);
Try this in your gulp file:
const elixir = require('laravel-elixir');
require('laravel-elixir-vue-2');
elixir(mix => {
mix.webpack('app.js');
});
And import your components like this:
import Test from './Components/Test.vue';
Vue.component('test', Test);

Categories

Resources