I am using VuePress version:
"devDependencies": {
"vuepress": "^2.0.0-beta.26"
}
and I can't add a simple .vue component to my .md page.
My Github LINK
Tried out the other solutions here, but nothing seems to help:
Solution1
Solution2
I was following the guide from the official VuePress documentation about components. But all I get is a zero size component (no content shown)
Would really appreciate any solutions.
EDIT:
to make it a bit simpler than to check my github. The whole project contains anyway only 2 files.
So what I did, is to make a new component.vue file in .vuepress/components:
<template>
<h1>Hello from my test component</h1>
</template>
<script>
export default {}
</script>
<style></style>
and am trying to add it in my README.md file:
# Hello VuePress
### test component
<TestComponent />
<kebab-case-test-component />
Screenshot for my folder tree:
From the VuePress 1.x to 2.x migration docs:
.vuepress/components/
Files in this directory will not be registered as Vue components automatically.
You need to use #vuepress/plugin-register-components, or register your components manually in .vuepress/clientAppEnhance.{js,ts}.
To configure auto component registration:
Install the #vuepress/plugin-register-components plugin:
npm i -D #vuepress/plugin-register-components#next
Add .vuepress/config.js with the following contents:
const { path } = require('#vuepress/utils')
module.exports = {
plugins: [
[
'#vuepress/register-components',
{
componentsDir: path.resolve(__dirname, './components'),
},
],
],
}
demo
Related
I wanted to create a project using this github repo as a base:
https://github.com/suresh-ramani/laravel-vue3-vite
The repo essentially enables a Laravel 9 full stack server-side rendered application to use vue3 within the blade template files. You can mount a vue3 app inside the blade files and import SFC (Single-File Components) ending in .vue to construct the application.
I want to enable Typescript INSIDE THE .VUE FILES. I am already aware of how to use vite to compile a basic .ts file.
I figured out the answer to my own question. To help others I'll take you through the steps. It's way easier than I thought it was going to be.
Step 1: Install TypeScript
System command: npm install typescript
Or
Laravel Sail Command: ./vendor/bin/sail npm install typescript
Step 2: Add lang attribute to your vue files
Add lang="ts" to your <script> tag
<template>
This is a test
</template>
<script lang="ts">
export default {
name: "App",
mounted() {
const message: string = "Testing 1 2 3"
console.log(message)
}
}
</script>
<style scoped>
</style>
I created a sample project to reproduce this issue: https://github.com/splanard/vue3-vite-web-components
I initialized a vue3 project using npm init vue#latest, as recommanded in the official documentation.
Then I installed Scale, a stencil-built web components library. (I have the exact same issue with the internal design system of my company, so I searched for public stencil-built libraries to reproduce the issue.)
I configured the following in main.ts:
import '#telekom/scale-components-neutral/dist/scale-components/scale-components.css';
import { applyPolyfills, defineCustomElements } from '#telekom/scale-components-neutral/loader';
const app = createApp(App);
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('scale-')
applyPolyfills().then(() => {
defineCustomElements(window);
});
And the same isCustomElement function in vite.config.js:
export default defineConfig({
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('scale-')
}
}
})]
// ...
})
I inserted a simple button in my view (TestView.vue), then run npm run dev.
When opening my test page (/test) containing the web component, I have an error in my web browser's console:
failed to load module "http://localhost:3000/node_modules/.vite/deps/scale-button_14.entry.js?import" because of disallowed MIME type " "
As it's the case with both Scale and my company's design system, I'm pretty sure it's reproducible with any stencil-based components library.
Edit
It appears that node_modules/.vite is the directory where Vite's dependency pre-bundling feature caches things. And the script scale-button_14.entry.js the browser fails to load doesn't exist at all in node_modules/.vite/deps. So the issue might be linked to this "dependency pre-bundling" feature: somehow, could it not detect the components from the library loader?
Edit 2
I just found out there is an issue in Stencil repository mentioning that dynamic imports do not work with modern built tools like Vite. This issue has been closed 7 days ago (lucky me!), and version 2.16.0 of Stencil is supposed to fix this. We shall see.
For the time being, dropping the lazy loading and loading all the components at once through a plain old script tag in the HTML template seems to be an acceptable workaround.
<link rel="stylesheet" href="node_modules/#telekom/scale-components/dist/scale-components/scale-components.css">
<script type="module" src="node_modules/#telekom/scale-components/dist/scale-components/scale-components.esm.js"></script>
However, I can't get vite pre-bundling feature to ignore these imports. I configured optimizeDeps.exclude in vite.config.js but I still get massive warnings from vite when I run npm run dev:
export default defineConfig({
optimizeDeps: {
exclude: [
// I tried pretty much everything here: no way to force vite pre-bundling to ignore it...
'scale-components-neutral'
'#telekom/scale-components-neutral'
'#telekom/scale-components-neutral/**/*'
'#telekom/scale-components-neutral/**/*.js'
'node_modules/#telekom/scale-components-neutral/**/*.js'
],
},
// ...
});
This issue has been fixed by Stencil in version 2.16.
Upgrading Stencil to 2.16.1 in the components library dependency and rebuilding it with the experimentalImportInjection flag solved the problem.
Then, I can import it following the official documentation:
main.ts
import '#telekom/scale-components-neutral/dist/scale-components/scale-components.css';
import { applyPolyfills, defineCustomElements } from '#telekom/scale-components-neutral/loader';
const app = createApp(App);
applyPolyfills().then(() => {
defineCustomElements(window);
});
And configure the custom elements in vite config:
vite.config.js
export default defineConfig({
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('scale-')
}
}
})]
// ...
})
I did not configure main.ts
stencil.js version is 2.12.1,tsconfig.json add new config option in stencil:
{
"compilerOptions": {
...
"skipLibCheck": true,
...
}
}
add new config option in webpack.config.js :
vue 3 document
...
module: {
rules:[
...
{
test: /\.vue$/,
use: {
loader: "vue-loader",
options: {
compilerOptions: {
isCustomElement: tag => tag.includes("-")
}
}
}
}
...
]
}
...
In one of my projects, I build a nice vue3 component that could be useful to several other projects. So I decided to publish it as an NPM package and share it with everyone.
I wrote the isolate component, build it and publish BUT I use Tailwind css to make the style.
When I publish and install the component everything is working BUT without the beauty of the css part.
I tried several configurations and alternative tools to generate the package that automatically add the tailwind as an inner dependency to my package.
Does someone have experience with this? how can build/bundle my component by adding the tailwind CSS instructions into it?
You're almost there
Since you've got your component working, the majority of the part has been done.
For configuring the styling of the component you need to identify the Tailwind CSS classes being used by your Vue component package and retain them in the final CSS that is generated by the Tailwind engine in your project.
Follow below steps in the project where you want to use your tailwind vue component package.
For Tailwind CSS V3
// tailwind.config.js
module.exports = [
//...
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
"./node_modules/package-name/**/*.{vue,js,ts,jsx,tsx}" // Add this line
// Replace "package-name" with the name of the dependency package
],
//...
]
For Tailwind CSS V2
// tailwind.config.js
module.exports = [
//...
purge: {
//...
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
"./node_modules/package-name/**/*.{vue,js,ts,jsx,tsx}" // Add this line
// Replace "package-name" with the name of the dependency package
],
//...
//...
}
]
The content property in the tailwind.config.js file defines file path pattern that the tailwind engine should look into, for generating the final CSS file.
For Pro users
You may also try to automate the above setup by writing an install script for your npm package to add this configuration to the tailwind.config.js file
References
Tailwind Docs - 3rd party integration
It's a bit difficult for someone to answer your question as you've not really shared the source code, but thankfully (and a bit incorrectly), you've published the src directory to npm.
The core issue here is that when you're building a component library, you are running npm run build:npm which translates to vue-cli-service build --target lib --name getjvNumPad src/index.js.
The index.js reads as follows:
import component from './components/numeric-pad.vue'
// Declare install function executed by Vue.use()
export function install (Vue) {
if (install.installed) return
install.installed = true
Vue.component('getjv-num-pad', component)
}
// Create module definition for Vue.use()
const plugin = {
install
}
// Auto-install when vue is found (eg. in browser via <script> tag)
let GlobalVue = null
if (typeof window !== 'undefined') {
GlobalVue = window.Vue
} else if (typeof global !== 'undefined') {
GlobalVue = global.Vue
}
if (GlobalVue) {
GlobalVue.use(plugin)
}
// To allow use as module (npm/webpack/etc.) export component
export default component
There is no mention of importing any CSS, hence no CSS included in the built version.
The simplest solution would be to include the index.css import in your index.js or the src/components/numeric-pad.vue file under the <style> section.
Lastly, I'm a bit rusty on how components are built, but you might find that Vue outputs the CSS as a separate file. In that case, you would also need to update your package.json to include an exports field.
When building a Vue library (component), according to Vue docs, you can set css.extract: false in vue.config.js to avoid the users having to import the CSS manually when they import the library into an app:
vue.config.js
module.exports = {
css: {
extract: false
}
}
However, when you do that, the icons are not displayed in the production build.
In this case I'm using #mdi/font and weather-icons. Neither of them load:
To reproduce
You can reproduce this with this Vue library (component):
Create new Vue project with vue create test
Clone the repo and put in the same directory as the Vue test project
In vue-open-weather-widget set css.extract: false in vue.config.js;
And comment out CSS import:
import 'vue-open-weather-widget/dist/vue-open-weather-widget.css'
Build vue-open-weather-widget with yarn build
Import it into the test Vue app with yarn add "../vue-open-weather-widget";
Serve the test app yarn serve
I have looked at your lib (nice component BTW). I created a build with css: { extract: false } and first looked at the behavior when importing vue-open-weather-widget.umd.js directly into an HTML file. And that worked without any problems.
The thing is that the fonts remain external in the dist after the build. And it seems that there is a problem to find the fonts when your component is loaded in a Webpack project (in our case Vue CLI project). I don't know why the fonts are not referenced correctly. But I have found another, and possibly a better solution.
As it is stated in the MDI docs, the use of the web fonts can negatively affect the page performance. When importing only one icon, all of them are imported, which in turn increases the bundle size. In such a small component this is more than suboptimal, especially for the component users. Therefore here is the alternative solution, also suggested by MDI:
Use #mdi/js instead of #mdi/font
Remove all #mdi/font references in your code and install deps:
npm install #mdi/js #jamescoyle/vue-icon
Replace all icons with SVG(e.g. in MainView.vue). Note that on this way only icons are included in the bundle that are used in your components:
...
<span #click="state.settings.view = 'settings'">
<svg-icon type="mdi" :path="mdiCogOutline"></svg-icon>
</span>
...
import SvgIcon from '#jamescoyle/vue-icon'
import { mdiCogOutline } from '#mdi/js'
...
components: {
SvgIcon
},
data () {
return {
mdiCogOutline: mdiCogOutline
}
},
Adjust vue.config.js:
module.exports = {
css: {
extract: false
}
}
Build component:
# i would also include --formats umd-min
vue-cli-service build --target lib --formats umd-min --name vue-open-weather-widget src/main.js
Now your dist contains only 192.68 KiB vue-open-weather-widget.umd.min.js and the component is ready to use over CDN or in a Vue CLI Project, without importing any CSS or fonts. I have tested both cases. Here is how it looks like:
Hope it helps you! Feel free to ask if you have further questions.
I create a web component with vue-cli.3 in order to use it in other projects with the following command:
vue-cli-service build --target lib --name helloworld ./src/components/HelloWorld.vue
The component has a dependency on lodash. I don't want to bundle lodash with the component because lodash is going to be provided by the host application, so I configure webpack in vue.config.js like below:
module.exports = {
configureWebpack: {
externals: {
lodash: 'lodash',
root: '_'
}
}
}
So this way, I successfully compile the component without lodash.
In the host application (the one that will use the component), I add the source path of the newly created and compiled component into index.html:
<script src="http://localhost:8080/helloworld.umd.js"></script>
Register the component in App.vue:
<template>
<div id="app">
<demo msg="hello from my component"></demo>
</div>
</template>
<script>
export default {
name: "app",
components: {
demo: helloworld
}
};
</script>
The helloworld component renders without problems. Every feature of the component works without problems but as soon as I call a method of lodash, I get;
Uncaught TypeError: Cannot read property 'camelCase' of undefined
which means the component cannot access the lodash library that the host application uses.
I need to find a way to use the already bundled libraries in the host application from the components.
Is there a way?
The Vue config you used should work (see GitHub demo), so maybe there's something missing in your setup. I've listed the pertinent steps to arrive at the demo:
In public/index.html of a VueCLI-generated project, import Lodash from CDN with:
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
In the library component (src/components/HelloWorld.vue), the _ global can be used without importing lodash. For example, display a computed property that formats the msg prop with _.camelCase.
To avoid lint errors, specify _ as an ESLint global (/* global _ */).
In vue.config.js, configure Webpack to externalize lodash:
module.exports = {
configureWebpack: {
externals: {
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_' // indicates global variable
}
}
}
}
In package.json, edit the build script to be:
"build": "vue-cli-service build --target lib --name helloworld ./src/components/HelloWorld.vue",
Run npm run build, and then edit dist/demo.html to also include the <script> tag above.
Start an HTTP server in dist (e.g., python -m SimpleHTTPServer), and open dist/demo.html. Observe the effect of _.camelCase (from step 2) without console errors.
GitHub demo