everyone.
I have a trivial doubt on making vue components.
I don't want to use browserify or webpack , cause I am working in django and it has most of it's templates in static files , although I read this , which does describe how to take in account both ( but that's for some other day ).
Problem :
I am making a single file component which I have to import and use, using my router but I can't, as the import just doesn't happen.
My Hello.vue
<template>
Some HTML code here.
</template>
<script>
module.exports = {
data() {
return {
coin : []
}
},
beforeRouteEnter (to, from, next) {
axios.get('my-django-rest-api-url')
.then(response => {
next(vm => {
vm.data = response.data
})
})
}
}
</script>
I have it in the index.html file itself , no other .js file,
<script>
import Hello from '#/components/Hello.vue'
Vue.use(VueRouter);
const dashboard = {template:'<p>This is the base template</p>'};
const profile = {
template: '#profile_template',
data () {
return {
profile_details: []
}
},
beforeRouteEnter (to, from, next) {
axios.get('my-api-url')
.then(response => {
next(vm => {
vm.profile_details = response.data
})
})
}
}
const router = new VueRouter({
routes: [
{ path: '/', component: dashboard },
{ path: '/profile', component: profile },
{ path: '/hello', component: Hello }
]
});
new Vue({
router : router,
}).$mount('#app');
</script>
What all I've tried :
1.<script src="../components/Hello.js" type="module"></script> and removing the import statement as suggested here
Replacing my Hello.js's code with this : export const Hello = { ...
Making a Hello.js file and importing it like this import Hello from '../components/Hello.js';
Error :
**Mozilla ( Quantum 57.0.4 64 bit ) ** : SyntaxError: import declarations may only appear at top level of a module
**Chrome ( 63.0.3239.108 (Official Build) (64-bit) ) ** :Uncaught SyntaxError: Unexpected identifier
P.S. : I have tried these in various combinations
Not a Vue.js guru, but here are a few perspectives that might help you.
Module loading is still not supported on modern browsers by default, and you'd need to set special flags in order to enable it (which the users of your app probably won't do).
If you insist on using import and export, you'd need Webpack. And most certainly Babel (or any other ES6 transpiler, e.g. Buble) as well.
If you prefer module.exports, then you'd need Browserify. It enables support for CommonJS in browser environments.
If neither is doable, then your best bet is defining Vue components in global scope. You can split them across separate files, and import each with a <script> individually. Definitely not the cleanest approach.
Single file components typically go inside of .vue files, but either way they require vue-loader which can be added and configured (again) with a bundler.
Last option is to just use an existing setup in place, if there is any (is there?). If you already have RequireJS, UMD, or something similar in place, adjust your components to fit that. Otherwise, use <script>s.
You are trying to do something which is not possible. Vue Single file components are not supported as raw component file by web browsers. The single file component is supposed to be compiled.
Please see this for more:
https://v2.vuejs.org/v2/guide/single-file-components.html
In Webpack, each file can be transformed by a “loader” before being included in the bundle, and Vue offers the vue-loader plugin to translate single-file (.vue) components.
A vue single file component is first "translated" (compiled) to pure javascript code which is use-able by browsers.
Related
I am writing a component library in/for react and using Rollup to bundle it. As part of the build process I am using Terser to make sure the bundle is as small as possible. As part of the minification process, Terser renames the variables and then renames then back at export. Like so:
export{_ as BtnResponsive,l as Button};
This works fine when importing my library into other ES modules. Like so:
import { BtnResponsive } from '#namespace/component-lib';
But when I create a Storybook story Button.stories.tsx and import my component like so:
import { ComponentStory, ComponentMeta } from '#storybook/react';
import { BtnResponsive } from '#namespace/component-lib';
export default {
title: 'Components/BtnResponsive',
component: BtnResponsive,
} as ComponentMeta<typeof BtnResponsive>;
const Template: ComponentStory<typeof BtnResponsive> = (args) => <BtnResponsive {...args} />;
export const Primary = Template.bind({});
Primary.args = { children: 'Primary', theme: 'primary' };
Storybook then renders the component in my story like
<_ theme="primary">
Primary
</_>
Storybook somehow doesn't respect the renamed export. Does anyone know how to either make storybook respect the component name? or know how I can adjust Terser so Storybook understands the name correctly?
Thanks in advance!
Terser apparently has options that you can use to prevent it from mangling function names. In my rollup.config.js I had to add the following:
terser({
keep_fnames: true,
})
I'm trying to load Vue 3 components in a asynchronous way. I've found that there is a function called
defineAsyncComponent
which is supposed to be used as follows:
const GameUI = defineAsyncComponent(()=>import(filePath));
app.component("GameUI", GameUI);
filePath in this context is exactly: './components/GameUI/GameUI.element.vue'
Running the app like this leads to the following error:
Uncaught (in promise) Error: Cannot find module './components/GameUI/GameUI.element.vue'
at eval (eval at ./src lazy recursive)
But... if I change the filePath code to import the path as a string:
const GameUI = defineAsyncComponent(()=>import('./components/GameUI/GameUI.element.vue'));
The app works, it does find the component.
I don't want to use constant strings, because I have a lot of components and I want to load them asynchronously.
One of my main goals to achieve this, is to load the webapp by parts, component by component whenever they are needed, instead of loading them all on start.
I've also find that if I append a comment as follows:
const GameUI = defineAsyncComponent(()=>import(/* webpackChunkName: "GameUI" */ './components/GameUI/GameUI.element.vue'));
The JavaScript part for the GameUI component, should have it's own chunk.js file, but I always keep getting everything in a couple .js chunk files, which contradicts the async loading I want to achieve.
I'm using vue-cli-service, and my vue.config.js looks like this:
module.exports = {
productionSourceMap: false,
css: {
loaderOptions: {
sass: {
additionalData: process.env.NODE_ENV === 'production'
? '$baseURL:"/dist/";'
: '$baseURL:"/";'
}
}
},
publicPath: process.env.NODE_ENV === 'production'
? '/dist/'
: '/',
devServer: {
https: true,
port:"",
host:'website.com',
disableHostCheck: true,
cert: (fs.readFileSync('cert.pem')+""),
key: (fs.readFileSync('privkey.pem')+""),
ca: (fs.readFileSync('ca.pem')+""),
}
};
I've already tried multiple stuff I've found online, but they are not that much explanatory. I'm literally doing the same as some online articles I've found and cannot find the problem on my side.
The two main problems are:
Cannot load .vue files from variables, only full strings.
Cannot split the code into different .js files for every async loaded component.
The answer to the first question:
Because there have some limitations of async import
.
What you are doing cannot work because you are using a variable as value to defineAsyncComponent.
According to the limitations of async import, you cannot import your component usinig a variable. Instead what you can do is:
// If the component name to call is GameUI.element
const component = 'GameUI.element' // can be comed from anyting
const GameUI = defineAsyncComponent(()=>import(`./components/GameUI/${component}.vue`));
app.component("GameUI", GameUI);
I'm quite new to Nuxtjs so I made a test project which purpose is merely the (of course) testing of Nuxtjs functionalities.
Currently I'm trying to create a simple custom module: afaik a module is basically a wrapper around a vou/js library/plugin, something like a high-level integration used to expose configurations on how the underlying library/plugin is imported and used in the Nuxt application.
So I'm trying with a simple module that declare some plain js classes that I'll use in my application, e.g. Order and Product, and that's what I came out with:
Directory structure
pages
the-page.vue
modules
classes
index.js
order.js
/modules/classes/index.js
const path = require('path')
export default function (moduleOptions) {
const { nuxt } = this
// add the debug plugin
this.addPlugin({
src: path.resolve(__dirname, 'order.js'),
})
}
/modules/classes/order.js
class Order {
constructor(id) {
this.id = id;
console.log('created order #' + this.id);
}
}
export {Order};
/nuxt.config.js
export default {
// ...
buildModules: [
// ...
'~/modules/classes'
],
// ...
}
/pages/the-page.vue
<script>
export default {
name: 'ThePage',
data () {
return {
}
},
methods: {
createOrder () {
const order = new Order(123)
}
}
}
</script>
The error
My defined class are still not imported in my pages:
/app/pages/the-page.vue
18:13 error 'order' is assigned a value but never used no-unused-vars
18:25 error 'Order' is not defined no-undef
Considerations
Probably I'm missing something about modules usage and/or implementation, but every tutorial I found starts with too complex scenarios, and since I'm at the beginning with Nuxtjs I need something easier to implement.
Ok, I found out that I was mistaken how NuxtJs modules are intended to work and was traying to do somenthing they are not intended for.
Nuxt modules cannot import js classes in every component of the application as I wanted to do, they just "add a property" to the main application instance that is made accessible through this.$<something>, like e.g. you can already do in simple Vue with the Vue Router or the Vuex store plugins that give access to the this.$router and this.$store properties.
NuxtJs modules just wrap simple plugins and expose configuration options to made.
We have a vanilla Vue/Vite setup and I'm receiving TypeError: Failed to fetch dynamically imported module on sentry logs.
It seems like the errors are correlated in time with new deployment to prod, although I don't have enough data to confirm. It doesn't happen on local and appears only on deployed code.
I've seen some similar questions for react's setups, but none with a satisfactory response.
I've also found a similar question regarding dynamically imported svgs, but our errors happen for full components.
The only place where we use dynamic imported components is on routing:
export const router = createRouter({
history: routerHistory,
strict: true,
routes: [
{
path: '/',
name: routes.homepage.name,
component: () => import('#/views/Home.vue'),
children: [
{
path: '/overview',
name: routes.overview.name,
component: () => import('#/views/Overview.vue'),
},
// other similar routes
],
},
],
});
Our deps versions:
"vue": "^3.0.9",
"vue-router": "^4.0.5",
"vite": "^2.0.5",
Any additional information on this issue and how to debug it would be much appreciated!
When you dynamically import a route/component, during build it creates a separate chunk. By default, chunk filenames are hashed according to their content – Overview.abc123.js. If you don't change the component code, the hash remains the same. If the component code changes, the hash changes too - Overview.32ab1c.js. This is great for caching.
Now this is what happens when you get this error:
You deploy the application
Your Home chunk has a link to /overview route, which would load Overview.abc123.js
Client visits your site
You make changes in your code, not necessarily to the Overview component itself, but maybe to some children components that Overview imports.
You deploy changes, and Overview is built with a different hash now - Overview.32ab1c.js
Client clicks on /overview link - gets the Failed to fetch dynamically imported module error, because Overview.abc123.js no longer exists
That is why the errors correlate with deployments. One way to fix it is to not use lazy loaded routes, but that's not a great solution when you have many heavy routes - it will make your main bundle large
In my case the error was caused by not adding .vue extension to module name.
import MyComponent from 'components/MyComponent'
It worked in webpack setup, but with Vite file extension is required:
import MyComponent from 'components/MyComponent.vue'
I had the exact same issue. In my case some routes worked and some didn't. The solution was relatively easy. I just restarted the dev server.
The accepted answer correctly explains when this error is triggered but does not really provide a good solution.
The way I fixed this is by using an error handler on the router. This error handler makes sure that when this error occurs (so thus when a new version of the app is deployed), the next route change triggers a hard reload of the page instead of dynamically loading the modules. The code looks like this:
router.onError((error, to) => {
if (error.message.includes('Failed to fetch dynamically imported module')) {
window.location = to.fullPath
}
})
Where router is your vue-router instance.
My situation was similar.
I found that my Quasar setup works fine on the initial page but not page that are loaded dynamically through an import('../pages/page.vue');.
Short response:
I replaced import('../pages/TestPage.vue') in the middle of the route file by import TestPage from '../pages/TestPage.vue' at the top.
More detailed response:
In my situation I don't expect to have much pages, a single bundle with no dynamic loading is fine with me.
The solution is to import statically every page I need.
In my routes.ts I import all the pages I need.
import IndexPage from '../pages/IndexPage.vue';
import TestPage from '../pages/TestPage.vue';
Then I serve them statically in my routes :
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: 'test', component: () => TestPage },
{ path: '', component: () => IndexPage }
],
},
// Always leave this as last one,
// but you can also remove it
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
},
];
I recently expriencied this. The error was caused by an empty href inside an a tag: <a href="" #click="goToRoute">. You can either remove the href or change the a tag to something else, ie. button. Let me know if this helps.
I had the same problem. I found that I had not started my project.
I am trying to implement StorybookJS into a SSR React app. Basic components work fine (button, headers etc). But anything that nests using dependencies like react-router-dom breaks.
Example:
We have a custom built <Link /> component that manages external links with a ternary. The external links flip to <a href= while internals use react-router-dom's <Link> imported as <ReactLink />. That code is like this:
// src/client/components/link/Link.js
import { Link as ReactLink } from "react-router-dom";
import { isLinkExternal } from "services/utils";
export const Link = ({ href, children = null, ...props }) => {
return isLinkExternal(href) ? (
<a href={href} {...props}>
{children}
</a>
) : (
<ReactLink to={href} {...props}>
{children}
</ReactLink>
);
};
The StorybookJS file for it looks like this:-
// link.stories.js
import React from "react";
import { Link } from "./Link"; // importing my component
export default {
title: "My Components/Link",
component: Link, // assigning my component
};
export const MyStoryBookLink = () => <Link href="/foo">I am a link</Link>;
Now, when i run Storybook it throws a load of errors, here are the recurring/main ones:-
ERROR in ./node_modules/redis-parser/lib/hiredis.js
Module not found: Error: Can't resolve 'hiredis' in '/Users/me/Documents/my-proj/node_modules/redis-parser/lib'
...
...
# ./.storybook/generated-stories-entry.js
I haven't touched anything redis / hiredis related and there is no such file as generated-stories-entry.js. The app works perfectly in Dev and Production so this is exclusively a Storybook env issue.
Next error down:
ERROR in ./node_modules/cache-manager-ioredis/node_modules/ioredis/lib/connectors/connector.js
Module not found: Error: Can't resolve 'net' in '/Users/me/Documents/myProject/node_modules/cache-manager-ioredis/node_modules/ioredis/lib/connectors'
Again, Though we are using cache-manager-ioredis, no idea why this is suddenly missing a module if it works fine on the app itself and all i'm trying to do is render a .
Next one:
Module not found: Error: Can't resolve 'tls' in cache-manager-ioredis
Same thing again^^
Then i get a load of these:
/Users/me/Documents/myProj/__mocks__/hiredis doesn't exist
.mjs
/Users/me/Documents/myProj/__mocks__/hiredis.mjs doesn't exist
.js
/Users/me/Documents/myProj/__mocks__/hiredis.js doesn't exist
.jsx
/Users/me/Documents/myProj/__mocks__/hiredis.jsx doesn't exist
.ts
/Users/me/Documents/myProj/__mocks__/hiredis.ts doesn't exist
.tsx
/Users/me/Documents/myProj/__mocks__/hiredis.tsx doesn't exist
.json
/Users/me/Documents/myProj/__mocks__/hiredis.json doesn't exist
.cjs
/Users/me/Documents/myProj/__mocks__/hiredis.cjs doesn't exist
Suggests it's looking for mocks to cover these sub sub sub dependencies, wherever they're needed.
I get the same for net and tls.
Finally, I get some:
Field 'browser' doesn't contain a valid alias configuration
I'm thinking somewhere in the depths of using react-router-dom/Link it is trying to find these, and they would only be there if webpack dev server / hot reloading made them accessible, OR if they were transpiled to be accessible from the production bundle.
But how do I mock these out? And is there an easy way to do it rather than manually mocking every sub dependency?
I have tried:
adding __mocks__/react-router-dom.js with an export const Link = ({props}) => <div>{children}</div> but it doesnt seem to kick in.
adding alias logic to .storybook/main.js:
webpackFinal: (config) => {
config.resolve.alias['react-router-dom'] = require.resolve('../__mocks__/react-router-dom.js');
return config;
},
Again, nothing seems to change.
using the storybook-react-router pkg but this seems quite old now, it configs to an old config.js file rather than main.js and uses the older storiesOf syntax. Also couldn't get to do anything.
manually installed tls, hiredis etc as --save-dev dependencies. But this seems hack. Why are these modules missing?
I cannot believe Storybook is this hard to use, more likely I'm overlooking something. I just want to mock something as common and basic as a from RRD.
What am I doing wrong? What am I missing?
I think I found the reason. It is because of node.js packages. To make it work, there are 2 solutions.
avoid importing node.js packages (usually related to SSR) for storybook related code. I use NX to structure my code, so I can easily move those part to its own library and only reference it from the top. (No storybook for the top App either in this solution)
skip those packages in the config.
something like
config.resolve.fallback = { http: false, net: false, tls: false, fs: false, dns: false, path: false };