unbuild
unbuild copied to clipboard
How to build Vue component library?
As per antfu's blog we can bundle Vue components. I have followed it but getting error. here are the files I have
// package.json
{
"name": "components",
"private": true,
"version": "0.0.0",
"scripts": {
"build": "unbuild"
},
"dependencies": {
"@vueuse/core": "^8.5.0",
"vue": "^3.2.21"
},
"devDependencies": {
"typescript": "^4.6.4",
"unbuild": "^0.7.4",
"vue-tsc": "^0.34.15"
}
}
// build.config.ts
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
entries: [
// bundling
'src/index',
// bundleless, or just copy assets
{ input: 'src/components/', outDir: 'dist/components' }, // this works but not generating MyComponent.vue.d.ts
],
declaration: true,
})
// src/index.ts
import InputAmount from './components/InputAmount.vue'
export { InputAmount }
<!-- src/components/InputAmount.vue -->
<script setup lang="ts">
import { watchDebounced, useMagicKeys } from '@vueuse/core'
import { computed, ref, watch } from 'vue'
const prop = defineProps({
placeholder: { default: '0', type: [String, Number] },
value: { default: '', type: [String, Number] },
min: { default: '0', type: [String, Number] },
max: { default: '', type: [String, Number] },
step: { default: '0.01', type: String },
readonly: { default: false, type: Boolean },
})
const emit = defineEmits({ change: (value: string) => value })
const input = ref(`${prop.value}` || '')
let wasValueChanged = false
const keys = useMagicKeys()
const shiftArrowUp = keys['Shift+ArrowUp']
const shiftCmd = keys['Shift+cmd']
const shiftCtrl = keys['Shift+Ctrl']
const arrowUp = keys['ArrowUp']
const steps = computed((): string => {
if ((shiftCmd.value || shiftCtrl.value) && arrowUp) return '10'
if (shiftArrowUp.value) return '1'
return prop.step
})
const onChange = () => {
// prevent infinite event loop
if (wasValueChanged || input.value === prop.value) {
wasValueChanged = false
return
}
emit('change', input.value)
}
watchDebounced(input, onChange, { debounce: 700 })
watch(
() => prop.value,
() => {
input.value = `${prop.value}`
wasValueChanged = true
}
)
</script>
<template>
<input
v-model="input"
class="unstyled-input w-full h-full text-base"
type="number"
:placeholder="`${placeholder}`"
:step="steps"
:min="min"
:max="max"
:disabled="readonly"
/>
</template>
<style>
/* stylelint-disable selector-no-vendor-prefix */
/* stylelint-disable property-no-vendor-prefix */
/* remove default style input */
.unstyled-input {
/* Some styles */
}
/* remove default style input */
.w-full {
width: 100%;
}
.h-full {
height: 100%;
}
.text-base {
font-size: 1rem; /* 16px */
line-height: 1.5rem; /* 24px */
}
</style>
when doing yarn build throws error
ℹ Building components 21:42:02
Error building /Users/mymac/magic/app/packages/components: Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
at error (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:1829:30)
at Module.error (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:12406:16)
at Module.tryParse (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:12783:25)
at Module.setSource (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:12688:24)
at ModuleLoader.addModuleSource (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:22144:20)
{
code: 'PARSE_ERROR',
parserError: SyntaxError: Unexpected token (1:0)
at Parser.pp$4.raise (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:19573:13)
at Parser.pp$9.unexpected (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:16867:8)
at Parser.pp$5.parseExprAtom (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18948:10)
at Parser.pp$5.parseExprSubscripts (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18740:19)
at Parser.pp$5.parseMaybeUnary (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18706:17)
at Parser.pp$5.parseExprOps (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18633:19)
at Parser.pp$5.parseMaybeConditional (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18616:19)
at Parser.pp$5.parseMaybeAssign (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18583:19)
at Parser.pp$5.parseExpression (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:18546:19)
at Parser.pp$8.parseStatement (file:///Users/mymac/magic/app/node_modules/rollup/dist/es/shared/rollup.js:17057:45) {
pos: 0,
loc: Position { line: 1, column: 0 },
raisedAt: 1
},
id: '/Users/mymac/magic/app/packages/components/src/components/InputAmount.vue',
pos: 0,
loc: {
column: 0,
file: '/Users/mymac/magic/app/packages/components/src/components/InputAmount.vue',
line: 1
},
frame: '1: <script setup lang="ts">\n' +
' ^\n' +
"2: import { watchDebounced, useMagicKeys } from '@vueuse/core'\n" +
"3: import { computed, ref, watch } from 'vue'",
watchFiles: [
'/Users/mymac/magic/app/packages/components/src/index.ts',
'/Users/mymac/magic/app/packages/components/src/components/InputAmount.vue'
]
}
I am also facing the same. I end up using vite.
So instead building them I am using bundleless, or just copy assets/components as it is by removing src/index as below
entries: [
// bundling
// 'src/index',
// bundleless, or just copy assets
{ input: 'src/components/', outDir: 'dist/' }, // this works but not generating MyComponent.vue.d.ts
],
which works fine, perhaps this might help you @jd-solanki
If someone still stuck with this & stubborn enougn for using this cool tool anyhow...........
Just Keep <template> block at top in your vue SFC file && it'll fix this isssue. Easy huh..!!
<!-- src/components/InputAmount.vue -->
<template>
........
</template>
<script setup lang="ts">
//
</script>
Easy, HuH..!
Still giving same error but now for templates
...
frame: '1: <template>\n' +
' ^\n' +
...
But, don't know why or how, it's working for me without giving me any error
can you please share working minimal reproduction?
I am getting similar errror when I tried unbuild in react.js library, but it complains about .png or .svg formats, I guess I need some sort of rollup plugin for images maybe like @rollup/plugin-image, but I am not sure how to configure in unbuild
I am getting similar errror when I tried unbuild in react.js library, but it complains about .png or .svg formats, I guess I need some sort of rollup plugin for images maybe like @rollup/plugin-image, but I am not sure how to configure in unbuild
@Digital-Coder you should be able to access the plugins array configuration using the rollup:options hook:
// build.config.ts
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
// other configs
hooks: {
'rollup:options'(_ctx, options) {
options.plugins.push(
// rollup plugin...
)
},
},
})
Hi @itsmnthn as I mentioned I ended up using vite. Here's how in case you want insights: https://github.com/jd-solanki/anu
// build.config.ts import { defineBuildConfig } from 'unbuild' export default defineBuildConfig({ // other configs hooks: { 'rollup:options'(_ctx, options) { options.plugins.push( // rollup plugin... ) }, }, })
@dwightjack I tried this trick to build .scss files but vscode isn't buying it...
Property 'push' does not exist on type 'Plugin | InputPluginOption[] | Promise<false | Plugin | NullValue | InputPluginOption[]>'.\n Property 'push' does not exist on type 'Plugin'.",
@amery I guess that's an issue with rollup typing because in the source code plugins is always an array:
- https://github.com/unjs/unbuild/blob/main/src/builder/rollup.ts#L112
- https://github.com/unjs/unbuild/blob/main/src/builder/rollup.ts#L190
The solution, in this case, could be to wrap the code in a type guard condition:
if (Array.isArray(options.plugins)) {
options.plugins.push(
// ...
)
}
The solution, in this case, could be to wrap the code in a type guard condition:
if (Array.isArray(options.plugins)) { options.plugins.push( // ... ) }
thank you @dwightjack, that did the trick. wouldn't this make a case for adding a plugins list to unbuild's RollupBuildOptions ? The amount of boilerplate just to add a rollup plugin
@amery I guess so. @pi0 What do you think about it?
From a more general point of view, I think that a plugin interface similar to the one provided by vite could help improve the extensibility of the tool. Something like:
// unbuild-plugin-myplugin
export default function MyPlugin({
hooks: {
'rollup:options'(_ctx, options) {
options.plugins.push(
// rollup plugin...
)
},
},
})
//
// build.config.ts
import { defineBuildConfig } from 'unbuild'
import MyPlugin 'unbuild-plugin-myplugin'
export default defineBuildConfig({
plugins: [MyPlugin()],
})
If you're still looking for one... https://github.com/wobsoriano/vue-sfc-unbuild
Supports vue 2 and 3
how did you solve it?
I am also facing the same.
Just add this code import 'vant/es/popup/style'
will report this error:
build.config.ts:
@itsmnthn @who-jonson @wobsoriano @amery @dwightjack
thank you @dwightjack, that did the trick. wouldn't this make a case for adding a plugins list to unbuild's RollupBuildOptions ? The amount of boilerplate just to add a rollup plugin
it doesn't seem to work @amery
Are those css files? What happens if you add the extension? @lixiaofa
Are those css files? What happens if you add the extension? @lixiaofa
To be precise, it is a. mjs file , It is a CSS for a third-party component library, but the file format is. mjs
Packaging error,
The error message is as follows:
@wobsoriano
unbuild does not process SFC files like .vue or .svelte
I think you have to use a compiler/transformer within the build tool, something like
- https://github.com/sxzz/unplugin-vue
Or only use mkdist
antfu:
I would suggest directly shipping SFC to npm and let userland plugin to compile it.
unbuilddoes not process SFC files like.vueor.svelteI think you have to use a compiler/transformer within the build tool, something like
- https://github.com/sxzz/unplugin-vue
Or only use
mkdistantfu:
I would suggest directly shipping SFC to npm and let userland plugin to compile it.
I tried, but still reported the same error
@sadeghbarati
The best is to create a basic repro so userland can play with it @lixiaofa
unbuild already covered those plugins no need to install them again
options.plugins.push(
- commonjs(),
- nodeResolve(),
- externals(),
postcss({
plugins: [],
})
)
This may help but this is not the way
unbuild+@vitejs/plugin-vue- use
vue-tscas dts file generator
unbuild-vue-transform.zip ( still not working when you add CSS content in the style section 😠)
From what I understand unbuild only works well when it's all about JS stuff
Something like @sveltejs/package is missing in the Vue ecosystem
The best is to create a basic repro so userland can play with it @lixiaofa
repro: https://github.com/lixiaofa/fast-plus
build.config.ts: https://github.com/lixiaofa/fast-plus/blob/master/internal/build/build.config.ts
import 'vant/es/popup/style': https://github.com/lixiaofa/fast-plus/blob/master/packages/components/sku/src/sku.vue
@wobsoriano @sadeghbarati Thank you
@lixiaofa I think the reproduction repo is too large and complex to understand the issue. From what I can understand from the screenshots, the task that is failing is buildModules which is calling rollup and not unbuild: https://github.com/lixiaofa/fast-plus/blob/4bee41cbb55bd1250422096cb89dda02e70466e1/internal/build/src/tasks/modules.ts#L16 is this correct?
My advice is to create a minimal reproduction to isolate the unbuild setup from all the other things going on in the project.
@lixiaofa I think the reproduction repo is too large and complex to understand the issue. From what I can understand from the screenshots, the task that is failing is
buildModuleswhich is calling rollup and not unbuild: https://github.com/lixiaofa/fast-plus/blob/4bee41cbb55bd1250422096cb89dda02e70466e1/internal/build/src/tasks/modules.ts#L16 is this correct?My advice is to create a minimal reproduction to isolate the unbuild setup from all the other things going on in the project.
I have conducted tests and found that importing 'vant/es/popup/style' without it can be packaged normally. If it is added, the above error will be reported.
You seem to be right @dwightjack
Hey @pi0 can we have a example/template in this repo for building vue component library?
I create a demo for building vue component library with unbuild + mkdist
And I have a component library (@leex/components) which also use unbuild + mkdist
When working with monorepo, how to stub the .vue files with mkdist while still ask rollup builder of unbuild to generate jiti wrapped modules for other modules to import, test and develop?
I am currently having questions when packages have multiple entries:
packages/some-vitepress-plugin/src/client/index: where the entry for Vue plugin that installs and exportInjectionKeyfor.vueSFC components. (I use Vue plugin here since VitePress requires me to register all the components forAppinstance of Vue). I tried to userollupto transpile them all todist/client/index.mjs.packages/some-vitepress-plugin/src/client/components: where all.vuefiles live in. I tried to usemkdistto transpile them all todist/client/components.
packages/some-vitepress-plugin/src/vite: where the Vite plugin to inject extra build time data (as virtual module), and transform markdown files located at. I tried to userollupto transpile them all todist/vite/index.mjs.
However, when working with such setup:
- I would encounter problems where the wrapped modules over
jitiwould result inFailed to resolve importerror when Vite tries to resolve dependencies for the needed modules. (others have mentioned such errors in this issue https://github.com/unjs/unbuild/issues/248) - I could switch to
mkdistfor them all where both https://github.com/wobsoriano/vue-sfc-unbuild and https://github.com/jsonleex/demo-mkdist suggests. However, according to what https://github.com/unjs/unbuild/issues/182 has explained, usingmkdistas builder will never generatejitiwrapper for TypeScript modules. How can I askmkdistto generate modules as.mjsand.jscorrespond topackage.json? In another word, how to stub.vuemodules, while generate workingjitiwrapped modules? - When using
mkdistwithrollup, even though I have setpatternsandinputDir, therollupbuild would still fail due to the missing modules to parse.vuemodules.
I understand that I can ship and include all the .vue to npm registry in traditional project setup, since there would be any problem with dual entries for components, and the development used vitepress and vite server will never to read and resolve modules with the values in exports fields in package.json.
The workflow seems broken when it comes to monorepo, how does everyone build and stub, even develop their UI compoents in multi-entries and monorepo packages? Does anyone have examples for me to take a look at?
https://github.com/unjs/unbuild/issues/80#issuecomment-2016442847
I finally came up an all-in-one unified solution for both developing, previewing, bundling for mixed project that has Vue components Library and Vite plugin all together.
I pushed the limits even further to make it possible to allow opt-in for unocss, i18n module bundling (with i18n-ally compatiblities), check it out on our project https://github.com/nolebase/integrations for VitePress plugins.
Configure for unbuild
export default defineBuildConfig({
entries: [
// Thanks to https://github.com/wobsoriano/vue-sfc-unbuild
// and https://github.com/jsonleex/demo-mkdist
// and all the discussions in https://github.com/unjs/unbuild/issues/80
// for the following configuration.
// Thanks to una-ui https://github.com/una-ui/una-ui/blob/main/packages/nuxt/package.json
// and the great examples of https://github.com/nuxt/module-builder/blob/5f34de12f934dd3c5f9b97bd919c4303736f2fc5/src/commands/build.ts#L41-L67
// excellent explanation in unjs/unbuild https://github.com/unjs/unbuild/issues/182
// for me to understand which entry points to use.
{ builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.vue'], loaders: ['vue'] },
{ builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.ts'], format: 'cjs', loaders: ['js'] },
{ builder: 'mkdist', input: './src/client', outDir: './dist/client', pattern: ['**/*.ts'], format: 'esm', loaders: ['js'] },
{ builder: 'rollup', input: './src/vite/index', outDir: './dist/vite' },
{ builder: 'rollup', input: './src/vite/index', outDir: './dist/vite' },
],
clean: true,
sourcemap: true,
declaration: true,
externals: [
'vite',
// builtins
...builtins,
],
rollup: {
emitCJS: true,
},
})
This configuration will:
- Use
mkdistto transpile all the sources under./src/clientto./dist/client. - Use
rollupto bundle all the sources under./src/viteto./dist/vite, while still be able to stub by usingjitifor all the sources under./src/viteto./dist/vite.
Configure for tsconfig.json and vite.config.(m)ts
And since the ./dist/client is bundled by file-to-file transpile, we have to configure both the tsconfig.json and vite.config.ts at the end user's side (not the "end users" who will install the released version of packages, but the VitePress docs dir or Vite's index.html located under root dir that lives in the monorepo itself).
Configure tsconfig.json
Add more paths to help tsc to redirect package resolve to the relative path:
{
// ...
"paths": {
"@scope/packagename/client/*": [
"./packages/packagename/src/client/*"
],
},
// ...
}
Configure vite.config.(m)ts
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
export default defineConfig({
resolve: {
alias: {
'@scope/packagename/client': resolve(__dirname, '../packages/packagename/src/client'),
},
},
})
Details of package.json
{
"name": "@scope/packagename",
"type": "module",
"version": "1.0.0",
// other fields
"sideEffects": false,
"exports": {
"./vite": {
"types": "./dist/vite/index.d.ts",
"import": "./dist/vite/index.mjs",
"require": "./dist/vite/index.cjs"
},
"./client": {
"types": "./dist/client/index.d.ts",
"import": "./dist/client/index.mjs",
"require": "./dist/client/index.js"
},
},
"main": "./dist/vite/index.cjs",
"module": "./dist/vite/index.mjs",
"types": "./dist/vite/index.d.ts",
"files": [
"README.md",
"dist",
"package.json"
],
"scripts": {
"dev": "unbuild --stub",
"stub": "unbuild --stub",
"build": "unbuild",
},
}
More examples can be found at the project I work on at https://github.com/nolebase/integrations
why?
@wen403 The error is saying that, probably, you have a reference to a dist/index.cjs in your package.json file, while the bundler generates dist/index.js