Vite: vue-i18n build fail - vue.js

Everything work fine in dev mode, but when try to npm run build, Unexpected token error in vue-i18n
import { createI18n } from 'vue-i18n';
import messages from '#intlify/vite-plugin-vue-i18n/messages'
const i18n = createI18n({
locale: 'en',
legacy: false,
fallbackLocale: 'en',
globalInjection: true,
messages
})
export default i18n;
//vite.config.js
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import path from 'path'
import vueI18n from '#intlify/vite-plugin-vue-i18n'
export default defineConfig({
plugins: [
vue(),
vueI18n({
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
// compositionOnly: false,
// you need to set i18n resource including paths !
include: path.resolve(__dirname, './src/locales/**'),
}),
],
resolve: {
alias: {
'#': path.resolve(__dirname, './src'),
},
},
})
Error:
[commonjs--resolver] Unexpected token (249:14) in E:/Work/Vue/vue-sample/node_modules/vue-i18n/dist/vue-i18n.runtime.esm-bundler.js
247: if (locales.length) {
248: locales.forEach(locale => {
249: global.mergeLocaleMessage(locale, messages[locale]);
^
250: });
251: }

Related

How to use Environment Variables inside Vue3+Vite component library?

I have created a component as part of my component library that I am building with Vue3 and Vite. Everything works well, except when I try to use environment variables. I want the app that consumes this component library to be able to provide the component with environment specific data.
I have played around and found that if I have a .env file as part of the component library project, I am able to access those variables, but I want to be able to provide that during runtime and not during build time.
Here is my vite.config.ts
import { defineConfig } from "vite";
import { resolve } from "path";
import vue from "#vitejs/plugin-vue";
import dts from "vite-plugin-dts";
export default ({ mode }) => {
return defineConfig({
optimizeDeps: {
exclude: ["vue-demi"],
},
plugins: [
vue(),
dts({
insertTypesEntry: true,
}),
],
server: {
open: true,
},
build: {
lib: {
entry: resolve(__dirname, "src/lib.ts"),
name: "complib",
fileName: "complib",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
exports: "named",
},
},
},
});
};
The entry looks like:
import { App, install } from "vue-demi";
import TestComp from "./components/TestComp.vue";
import "./tailwind.css";
install();
export default {
install: (app: App) => {
app.component("TestComp", TestComp);
},
};
export { Header };
And here is a minimal component TestComp.vue:
<script setup lang="ts">
import { onMounted } from "vue";
onMounted(() => {
console.log(import.meta.env.VITE_TEST_VAR);
});
</script>
<template>
<span>Test Comp</span>
</template>

Sub routes inside the vue3 + vite micro frontend

I am using vue3 + vite and a plugin
#originjs/vite-plugin-federation
to build a micro frontend. One app will be the host and one will be the remote, both will have their own routing. Is there a way to navigate remote app inside the host app.
If I export a single component from the remote app it is working, but if I export App.js with routing it is not working, can anybody provide general guidelines to this problem.
vite config of remote:
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import vueJsx from "#vitejs/plugin-vue-jsx";
import federation from "#originjs/vite-plugin-federation";
const dependencies = require("./package.json").dependencies;
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
federation({
name: "remote-app",
filename: "remoteEntry.js",
exposes: {
"./Test": "./src/App.vue",
},
shared: [{ ...dependencies }, "vue", "vue-router"],
}),
],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
vite.config of host:
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import vueJsx from "#vitejs/plugin-vue-jsx";
import federation from "#originjs/vite-plugin-federation";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
federation({
name: "host-app",
remotes: {
remote: "http://127.0.0.1:5173/dist/assets/remoteEntry.js",
},
shared: ["vue"],
}),
],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});

How use vue-i18n with vue2, vite?

i'm migrating from webpack to vite, but there is a problem that I can't find a plugin to use i18n
I tried to use #intlify/vite-plugin-vue-i18n: 6.0.1, it doesn't seem to be work
now my package version:
vue: 2.6.11
vue-i18n: 8.17.0
#kazupon/vue-i18n-loader: 0.5.0
#intlify/vite-plugin-vue-i18n: 6.0.1
vite: 2.9.15
vite-plugin-vue2: 2.0.2
vite.config.js
/* cSpell:disable */
import { defineConfig } from 'vite';
const { resolve } = require('path');
import { createVuePlugin } from 'vite-plugin-vue2';
import copy from 'rollup-plugin-copy';
import { viteCommonjs } from '#originjs/vite-plugin-commonjs';
import clear from 'rollup-plugin-clear';
import vueI18n from '#intlify/vite-plugin-vue-i18n';
import { createI18nPlugin } from '#yfwz100/vite-plugin-vue2-i18n';
const destDir = `../var/dist/views`;
const host = 'localhost';
let filePort;
try {
const port = require('../port');
filePort = port && port.front;
// eslint-disable-next-line no-empty
} catch (error) {}
const listenPort = filePort || '10210';
const pages = {
cn: {
dir: 'pages',
template: 'cn.html',
entry: 'cn.js'
},
'vue-test': {
dir: 'vue-test/index',
template: 'index.html',
entry: 'index.js'
}
};
const multiplePagePath = 'src/pages';
const copyFileList = [];
Object.values(pages).forEach(item => {
copyFileList.push({
src: `${multiplePagePath}/${item.dir}/${item.template}`,
dest: destDir + '/' + item.dir,
transform: (contents, filename) =>
contents
.toString()
.replace(
'<!-- viteDevelopmentCopyReplaceHref -->',
`<script src="//${host}:${listenPort}/${multiplePagePath}/${item.dir}/${item.entry}" type="module" ></script>`
)
});
});
export default defineConfig({
resolve: {
alias: { src: resolve(__dirname, './src') },
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
port: listenPort,
// https: true,
hmr: { host },
origin: `//${host}:${listenPort}`
},
plugins: [
createVuePlugin(),
clear({
targets: ['../var']
}),
copy({
targets: [...copyFileList, { src: 'src/pages/*.html', dest: destDir }, { src: 'src/pages/layout', dest: destDir }],
verbose: true,
hook: 'buildStart'
}),
vueI18n({
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
// compositionOnly: false,
// you need to set i18n resource including paths !
// include: resolve(__dirname, './path/to/src/locales/**'),
compositionOnly: false
})
]
});
index.vue
<i18n>
{
"en-us": {
"language": "Language",
"hello": "hello, world!"
},
"zh-cn": {
"language": "言語",
"hello": "こんにちは、世界!"
}
}
</i18n>
<template>
<div id="app">
<p>{{$t('language')}}</p>
</div>
</template>
<script>
</script>
when i open the page, the text has not been translated and there is a warning in console:
[vue-i18n] Cannot translate the value of keypath 'language'. Use the value of keypath as default
Can anyone help me on this? Thanks in Advance
#intlify/vite-plugin-vue-i18n does not support custom block in Vue 2.
You should use unplugin-vue-i18n with vue-i18n-bridge.
Minimal examples of Vue2 + VueI18n custom block + Vite:
Vue<=2.6: https://stackblitz.com/edit/vitejs-vite-wk6hhj
Vue 2.7: https://stackblitz.com/edit/vitejs-vite-elfdtq
I18n Legacy API:
Vue<=2.6: https://stackblitz.com/edit/vitejs-vite-ed3cmt

Using vue slots in library gives currentRenderingInstance is null

I am creating a Vue component library with Rollup, but when I use slots it gives me the following error:
Uncaught (in promise) TypeError: currentRenderingInstance is null
I made a very simple component in my library:
<script setup></script>
<template>
<button>
<slot></slot>
</button>
</template>
<style scoped></style>
Then I simply use it like this:
<ExampleComponent>
Text
</ExampleComponent>
If I remove the slot and replace it with a prop or hard-coded text, everything works fine.
This is my rollup.config.js:
import { defineConfig } from 'rollup';
import path from 'path';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import vue from 'rollup-plugin-vue';
// the base configuration
const baseConfig = {
input: 'src/entry.js',
};
// plugins
const plugins = [
vue(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
}),
// process only `<style module>` blocks.
postcss({
modules: {
generateScopedName: '[local]___[hash:base64:5]',
},
include: /&module=.*\.css$/,
}),
// process all `<style>` blocks except `<style module>`.
postcss({ include: /(?<!&module=.*)\.css$/ }),
commonjs(),
];
const external = ['vue'];
const globals = {
vue: 'Vue',
};
export default [
// esm
defineConfig({
...baseConfig,
input: 'src/entry.esm.js',
external,
output: {
file: 'dist/vue-my-lib.esm.js',
format: 'esm',
exports: 'named',
},
plugins,
}),
// cjs
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.ssr.js',
format: 'cjs',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
// iife
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.min.js',
format: 'iife',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
];
Any idea about the problem?
After a whole day of searching, I found the solution (here and here). It's a problem with using a library locally (e.g., through npm link) where it seems there are two instances of Vue at the same time (one of the project and one of the library). So, the solution is to tell the project to use specifically its own vue through webpack.
In my case, I use Jetstream + Inertia, so I edited webpack.mix.js:
const path = require('path');
// ...
mix.webpackConfig({
resolve: {
symlinks: false,
alias: {
vue: path.resolve("./node_modules/vue"),
},
},
});
Or if you used vue-cli to create your project, edit the vue.config.js:
const { defineConfig } = require("#vue/cli-service");
const path = require("path");
module.exports = defineConfig({
// ...
chainWebpack(config) {
config.resolve.symlinks(false);
config.resolve.alias.set("vue", path.resolve("./node_modules/vue"));
},
});
Thanks to #mikelplhts
On vite + esbuild I used:
export default defineConfig({
...
resolve: {
alias: [
...
{
find: 'vue',
replacement: path.resolve("./node_modules/vue"),
},
],
},
...

export 'default' (imported as 'Vue') was not found in 'vue

I'm trying to get the url of the backend, but I get an error while importing and it's not clear how to fix it.
warning in ./src/store/index.js
"export 'default' (imported as 'Vue') was not found in 'vue'
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
backendUrl: "http://127.0.0.1:8000/api/v1"
},
mutations: {},
actions: {},
modules: {},
getters: {
getServerUrl: state => {
return state.backendUrl
}
}
})
export default store
working version:
import { createStore } from "vuex";
const store = createStore({
state: {
backendUrl: "http://127.0.0.1:8000/api/v1"
},
mutations: {},
actions: {},
modules: {},
getters: {
getServerUrl: state => {
return state.backendUrl
}
}
})
export default store
If you are using the vue-cli, I have found that the solution is to modify vue.config.js to include the devServer property. See the Vue CLI documentation
module.exports = {
devServer: {
disableHostCheck: true,
proxy: {
'/api-ezbook': {
target: 'http://localhost:80',
ws: false
}
},
public: 'http://localhost:8080'
}
// use to deploy
publicPath: '/'
// use to deploy to live server
// publicPath: '/location/on/server'
// in production:
// publicPath: '/'
}