I love vue.js because of its simplicity, which means I can hack a quick one-page SPA with modern, intuitive data-binding syntax and no complex toolchain.
I also love the idea of single-file components which means there is a single place (*.vue file) where each component stores DOM, styling and scripted functionality.
However, I want to use single-file components without wasting time on managing a build process every time I put an app together. In short, I want the benefits of component management without the overhead of a build toolchain, which means letting the browser do the heavy lifting for bootstrapping each *.vue file via XMLHttpRequest and DOM rendering. Making sure that we replace module.exports and import calls with corresponding Vue.component() functionality.
I'd love to know if anyone has come across a client-side (only) solution for using *.vue files on the browser. Surely this has been done already?
I'm absolutely certain this doesn't exist yet, because while it might seem relatively easy, certain functionalities would make it quite difficult to implement. For example:
You don't necessarily import just other .vue components, you can import random external dependencies. Which means that the browser now needs to download and parse npm modules, handle their dependencies, etc.
Different sections of your .vue component (template, logic and style) can be written in languages other than HTML, JS and CSS. Which means the browser now also needs to download a compiler/transpiler for Jade, CoffeeScript, LESS or whatever else you're using and run your code through it. Mind, there's no guarantee that such a transpiler written in JavaScript actually exists, because a node module used in a regular build process could be just a wrapper for some external library which can't be run in a browser.
Styling in a .vue component can be scoped, which means that you now need to parse the template of a component to insert randomly generated IDs as element attributes AND parse the styling of the same component to insert those same IDs in your CSS selectors so that your styling ends up being scoped.
And those are just the most obvious ones off the top of my head. Sure, you could severely limit yourself and not use any of those features, but then it's not really a .vue component anymore, is it?
If you really want to avoid a build process at all costs and are willing to accept the limitations of not using any of the features above, why not just use a single JS file:
$(body).append(`<style>
// styling goes here
</style>`);
var myTemplate = `
// template goes here
`;
Vue.component('my-component', {
template: myTemplate
// component logic goes here
})
You have to load them in the correct order, but there you have it, a poor man's single file component.
Another way is use: http-vue-loader
Load .vue files directly from your html/js. No node.js environment, no build step.
https://cdn.jsdelivr.net/npm/http-vue-loader#1.4.1/src/httpVueLoader.min.js
Same to in unpkg cdn
https://unpkg.com/http-vue-loader
Here a example
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/http-vue-loader"></script>
<script>
new Vue({
el: '#app',
components: {
'header': httpVueLoader('/components/header.vue'),
'nav-bar': httpVueLoader('/components/navbar.vue'),
'aside': httpVueLoader('/components/aside.vue'),
'content': httpVueLoader('/components/content.vue'),
'footer': httpVueLoader('/components/footer.vue')
}
});
</script>
Or you can load your components from external like
'MyHelloWorldComponent': httpVueLoader('https://my-cdn-or.github.io/path/HelloWorld.vue'),
See the example at : https://codepen.io/mikechen2017/pen/wEdbBN/
It's 2020 and Evan You wrote https://github.com/vuejs/vite just last week.
I'd love to know if anyone has come across a client-side (only) solution...
Vite has a server, but it feels like the old days of Web when we just had Notepad. I had run the demo in less than 5 minutes, it's that easy.
it covers or aims to cover the finer details that #mzgajner mentions
For now, I would say that it's only gotcha is that you are in Vue 3 beta realm right away if you use it. No Vue 2.x.
However, I want to use single-file components without wasting time on managing a build process every time I put an app together. In short, I want the benefits of component management without the overhead of a build toolchain
I share the sentiment and decided to solve this problem with vue-blocks. Just a single script tag to get going, no build tools required, completely client-side.
It can load vue files (with some limitations though) from the server jsfiddle example:
<template src="path/to/vue-file.vue"></template>
Vue Blocks allows you to write multiple vue components in the html document, like so:
<template component="sample-component">
<div>
<h1>Sample component</h1>
</div>
<style>
</style>
<script>
export default {
data() {
return {}
},
mounted() {},
methods: {
xx() {
}
}
}
</script>
</template>
A working demo in jsfiddle: https://jsfiddle.net/o48L0y9j/
Related
There is something I find very confusing when working in React.js.
There are plenty of examples available on internet which use .js files with React but many others use .jsx files.
I have read about JSX files and my understanding is that they just let you write HTML tags within your JavaScript.
But the same thing can be written in JS files as well.
So what is the actual difference between .js and .jsx ?
There is none when it comes to file extensions. Your bundler/transpiler/whatever takes care of resolving what type of file contents there is.
There are however some other considerations when deciding what to put into a .js or a .jsx file type. Since JSX isn't standard JavaScript one could argue that anything that is not "plain" JavaScript should go into its own extensions ie., .jsx for JSX and .ts for TypeScript for example.
There's a good discussion here available for read
In most of the cases it’s only a need for the transpiler/bundler, which might not be configured to work with JSX files, but with JS! So you are forced to use JS files instead of JSX.
And since react is just a library for javascript, it makes no difference for you to choose between JSX or JS. They’re completely interchangeable!
In some cases users/developers might also choose JSX over JS, because of code highlighting, but the most of the newer editors are also viewing the react syntax correctly in JS files.
JSX tags (<Component/>) are clearly not standard javascript and have no special meaning if you put them inside a naked <script> tag for example. Hence all React files that contain them are JSX and not JS.
By convention, the entry point of a React application is usually .js instead of .jsx even though it contains React components. It could as well be .jsx. Any other JSX files usually have the .jsx extension.
In any case, the reason there is ambiguity is because ultimately the extension does not matter much since the transpiler happily munches any kinds of files as long as they are actually JSX.
My advice would be: don't worry about it.
As other mentioned JSX is not a standard Javascript extension. It's better to name your entry point of Application based on .js and for the rest components, you can use .jsx.
I have an important reason for why I'm using .JSX for all component's file names.
Actually, In a large scale project with huge bunch of code, if we set all React's component with .jsx extension, It'll be easier while navigating to different javascript files across the project(like helpers, middleware, etc.) and you know this is a React Component and not other types of the javascript file.
As already mentioned, there is no difference, if you create a file with .jsx or .js.
I would like to bring another expect of creating the files as .jsx while creating a component.
This is not mandatory, but an architectural approach that we can follow. So, in large projects we divide our components as Presentational components or Container components. Just to brief, in container components we write the logic to get data for the component and render the Presentational component with props. In presentational components, we usually donot write functional logic, presentational components are used to represent the UI with required props.
So, if you check the definition on JSX in React documents.
It says,
const element = <h1>Hello, world!</h1>;
It is called JSX, and it is a syntax extension to JavaScript. We
recommend using it with React to describe what the UI should look
like. JSX may remind you of a template language, but it comes with
the full power of JavaScript.
JSX produces React “elements”. Instead of artificially separating
technologies by putting markup and logic in separate files, React
separates concerns with loosely coupled units called “components”
that contain both.
React doesn’t require using JSX, but most people find it helpful as a
visual aid when working with UI inside the JavaScript code. It also
allows React to show more useful error and warning messages.
It means, It's not mandatory but you can think of creating presentational components with '.jsx' as it actually binds the props with the UI. and container components, as .js files as those contains logic to get the data.
It's a convention that you can follow while creating the .jsx or .js files, to logically and physically separate the code.
Besides the mentioned fact that JSX tags are not standard javascript, the reason I use .jsx extension is because with it Emmet still works in the editor - you know, that useful plugin that expands html code, for example ul>li into
<ul>
<li></li>
</ul>
JSX isn't standard JavaScript, based to Airbnb style guide 'eslint' could consider this pattern
// filename: MyComponent.js
function MyComponent() {
return <div />;
}
as a warning, if you named your file MyComponent.jsx it will pass , unless if you edit the eslint rule
you can check the style guide here
Depending on the IDE or editor, .jsx has a different file icon :P. And it's a good practice to know what file it is without reading the code. The bundler and compiler might know it and will take care of everything, but telling the difference between .jsx and .js from just the file name will help you as a developer a lot.
EDIT: jsx is more than js, it is javascript + xml, which allows you to write html inside a js file without using template strings. For this reason it's a good practice to use .jsxfor your react files, instead of .js (which is also valid).
if you use .jsx it will be treated as a react page so its features will be applied by extensions automatically. for example if you use emmet in .jsx file, .container, this will create a div with className not class
<div className="container"></div>
if you apply the same emmet inside a js file, you would get this:
<div class="container"></div>
copied from: https://reactjs.org/docs/introducing-jsx.html
Why JSX? React embraces the fact that rendering logic is inherently coupled with other UI logic: how events are handled, how
the state changes over time, and how the data is prepared for display.
Instead of artificially separating technologies by putting markup and
logic in separate files, React separates concerns with loosely coupled
units called “components” that contain both. We will come back to
components in a further section, but if you’re not yet comfortable
putting markup in JS, this talk might convince you otherwise.
React doesn’t require using JSX, but most people find it helpful as a
visual aid when working with UI inside the JavaScript code. It also
allows React to show more useful error and warning messages.
I'm wondering what's the best way about adding a front end, componentized framework to a Wordpress site without using the Rest API.
I'm taking over two sites built with the Woocommerce Storefront theme, and I'd like to add a reliable front end library. Would it be best to just build my own as I need it? I'd like to avoid jQuery as I find it gets messy pretty quickly.
Would a good course of action be to build a plugin which generates a Post type with the framework added in, or is there a way I can add my framework to the whole site and implement it incrementally.
If you start a new project from scratch, I would recommend using Sage: https://roots.io/sage/.
One big deal when it comes to use React / Vue.js for any kind of projects is you need to setup the build (using Webpack for example), to compile them and get the best of out these frameworks. Sage takes care of these tasks for you and have webpack and browserify integrated so you have hot loading for dev and proper build for production. That's really an advantage.
With your case, because your sites have been built using Storefront, so integrate fully with Sage seems to be not an option, however, you can still borrow some ideas from Sage.
Sage set it scripts up in the way that your script can be separated into routes, though these routes are not exactly the same as ones of a single page app. Basically, they have an util function called Router, which will execute JS functions based on the classes inserted into the body element. I find it works extremely well with Vue.js and React. For instances: in your homepage, you want to place couple of Vue components inside a <div id="homepage"> element, you can define it as follows:
export default {
init() {
new Vue({
el: '#homepage',
name: 'HomePageApp',
components: {
...
},
});
},
finalize() {
// JavaScript to be fired on the home page, after the init JS
},
};
Then import and add it to your Router:
const routes = new Router({
...
// Home page
homepage,
});
I recommend having a look at how Sage does that in your Github repo, it's pretty straight forward and guarantee a well-organised, well-structured front-end: https://github.com/roots/sage/blob/master/resources/assets/scripts/main.js
i'am creating spa application using vuejs and i find out that i have 3 option in loading my javascript library like bootstrap.js or jquery.js and other javascript library:
1.
first is by include all javascript library that i will use in my application in index.html where my vuejs application will live but i find that there is some javascript library that not working to well
ex: there is some javascript library that calculate page height by selecting some div with specific id="page-container", but that div not loaded when page is rendered from server, so at that moment the javascript will throw error since id="page-container" not exist yet.
2.
second is by adding it like this to all my javascript library js
// before you use your files in some components,you should package them
// your local files
export default { //export your file
your_function(){ // defined your function
...
}
}
// now your can use it
// your component file
<script>
import local_file from 'your_file_relative_path'
//now you can use it in the hook function
created(){ //or other hook function
local_file.your_function() //call your function
}
</script>
but that mean i need to change every javascript library that i use...
3.
third is by adding it using npm, and just in the vue component import it, it works okay and feels more natural but not all my javascript library are in npm, some of them is admin template related that i bought from themeforest and will never be in npm.
so which one is a better way or maybe there is much more better way that those 3 option that i find out? its hard to find any tutorial or discussion that mention adding other javascript library to spa vuejs most of them just put a bootstrap into index.html and done.
Well, If your library exist in NPM, then this is the best option, because then you have this option to import only the part of the script that you need for certain components, for example, fontawesome library, you can import only the icons that you need instead of import all of them!
but if your script is not in NPM, the best option is to run your script in beforeMount or beforeCreate of the component that the script needed to run.
the third way which is add the link reference on html is not really suggested, since it will be global and will reduce the performance.
I have a few EXTERNAL scripts that need to be loaded on various pages, such as Google Places Autocomplete, Facebook APIs, etc.
Obviously it does not make sense to load them on every route, however the documentation does not address this rather common scenario.
Furthermore, the Vue instance mounts onto a tag within the body, since
the mounted element will be replaced with Vue-generated DOM in all cases. It is therefore not recommended to mount the root instance
to < html > or < body >.
How are real world applications currently dealing with this situation?
I recommend using https://www.npmjs.com/package/vue-head, it is exactly designed to inject the data you want from your component into the document's head.
Perfect for SEO title and meta tags.
To be used like so:
export default {
data: () => ({
title: 'My Title'
}),
head: {
// creates a title tag in header.
title () {
return {
inner: this.title
}
},
meta: [
// creates a meta description tag in header.
{ name: 'description', content: 'My description' }
]
}
}
This isn't addressed in documentation because it's not Vue's job. Vue is meant for creating, among other things, single page applications (SPA). In a single page application you typically load all your vendor scripts (Google, Facebook, etc.) and your own scripts and styles the first time the site loads.
A lot of real world applications just bundle all their vendor scripts into a single file (example: vendor.js) using Webpack, Gulp, Grunt or some other bundling tool. The rationale is that you can pack all those scripts into a single file, minify them, serve them with gzip compression and then it's only a single request.
Smarter bundlers like Webpack and Browserify can walk the dependency tree if you're using require() or import to import your modules. This can be allow you to split your dependencies into several logical chunks so components and libraries only load load with their dependencies if they themselves are loaded.
We had this issue as well. We load JavaScripts by other means. We created a library that does this for us (quick and dirty, observing browser events and adding the JavaScript tag). This library also, implements a mediator pattern (https://addyosmani.com/largescalejavascript/#mediatorpattern) fires an event of "page:load" (custom for us) at the very end once all libraries have been loaded.
Our VueJS components are executed only when that event fires. This also allowed us to put Vue components in the header tag instead of body, as the browser will load it, but not execute the function until the event is fired.
var loadVueComponents=function()
{
var myComponents=new Vue({....});
};
Mediator.subscribe("page:load",loadVueComponents);
Before I get downvotes for not using Webpack or any of those other tools, this was an old application with a lot of JavaScripts (some cannot be minified or even concatenated/bundle with other files) and we needed to add some new components (now using Vue) and trying to disrupt as little as possible existing pages (mediator pattern was already implemented and loading dynamic libraries based on page attributes)
I think you are talking about some external JS which are not part of node-modules and want to retrieve from external source (http://your-external-script) then you can go for dynamic loading of JS script tag. Put this code somewhere like you first landing screen of SPA in before transition event.
var script = document.createElement('script');
script.src = "htpps://your-external-script.js";
document.head.appendChild(script); //or something of the likes
This will make your external file available in global scope and then you can use it anywhere.
Note: this scenario is where you dont haev node-moduels for library or you dont want to put as load modules
I am working on an isomorphic javascript app with express + react. We started out using jade for server side templates for static content, but combining the two is quickly becoming unwieldy. We have ended up with something like this:
In the express routes:
router.get("/", function(req, res) {
var webpackStats = require('../../config/webpack-stats.json');
var reactHtml = React.renderToString(HiwApp({}));
var slideshowHtml = React.renderToString(slideshowApp({}));
var config = {
webpackStats: webpackStats,
reactOutput: reactHtml,
slideshowHtml: slideshowHtml
};
res.render("how_it_works/howitworks", config);
});
In Jade:
body
.company-logo.center
#react-main-mount
!= reactOutput
include ./content_block_1.jade
include ./content_block_2.jade
#slideshow-main-mount
!= slideshowHtml
This is very brittle-if we want jsx then a jade template then more jsx, we have to make sure we get the order right.
My idea is to do it all with jsx. I know there is React.renderToStaticMarkup for this sort of thing, but that doesn't solve the problem of mixing dynamic with static pages.
The big questions: if we decide to do all of this with jsx (say layout.jsx which contains all components), then call React.renderToString(App({});, will this be a major performance hit? If so, is there a better way to do it to easily combine static and dynamic blocks?
Although this may be a tiny bit off topic: We stuck with jade templates.
Basically we wanted the flexibility to use a non-react + flux architecture for areas of the site when and if that need arose. Our site is basically made up of a number of smaller SP apps: Site, UserAccount, Team and Admin.
Why did we do this?
Smaller filesize and overhead for users who are not accessing all sections of the site.
Option to "opt out" of React and flux if and when the need arises.
Simpler, server side authentication.
The way we have done it successfully was to render a JSX shell template (Html.jsx) on the server using React.renderToStaticMarkup() and then send it as the response to every server-side express route request that is meant to deliver some HTML to the browser. Html.jsx is just a shell containing html head information and GA scripts etc. It should contain no layout.
// Html.jsx
render(){
return (
<html>
<head>
// etc.
</head>
<body>
<div
id="app"
dangerouslySetInnerHTML={{__html: this.props.markup}}>
</div>
</body>
<script dangerouslySetInnerHTML={{__html: this.props.state}</script>
<script>
// GA Scripts etc.
</script>
</html>
)
}
Remember it is totally fine and even recommended to use dangerouslySetInnerHTML on the server when hydrating your app.
Dynamic layout should be done with your your isomorphic components through a hierarchy of components based on their state/props configuration. If you happen to be using React Router, then your router will render view handlers based on the routes you provide it so that means you don't need to manage that yourself.
The reason we use this technique is to architecturally separate our "App" which is isomorphic and responds to state from our server-side template shell which is just a delivery mechanism and is effectively boiler plate. We even keep the Html.jsx template amongst all the express components within our app and do not let it mix with the other isomorphic React components.
One of the most helpful resources I found for working out React/isomorphic architecture was https://github.com/yahoo/flux-examples/tree/master/react-router which is where we stole this technique from.
We explored the idea of integrating handlebars as a templating engine for client's devs using our products in the future but decided that it was less complex to write our own DSL in JSX and use some simple parsing routines to parse our HTML-like DSL to JSX by adding things like export default (ES6 module syntax) at the start of the template and then import the template to a rendering component.
You could of course follow that line of thought and use a jade compiler to spit out the template and then add module syntax around that if you think separate jade files are essential. I also noticed this project as well although I have not explored it in anger: https://github.com/jadejs/react-jade.