vuejs / vue-cli

🛠️ webpack-based tooling for Vue.js Development
https://cli.vuejs.org/
MIT License
29.75k stars 6.33k forks source link

Build Vue Components as standalone components #1065

Open kayandra opened 6 years ago

kayandra commented 6 years ago

Version

3.0.0-beta.6

Reproduction link

https://codesandbox.io/s/k2qojnor8o

Steps to reproduce

I am using Vue cli and I have a components directory structure like this

- components
  - button
    - button.scss
    - button.vue
    - index.js
  index.js // imports all components

What is expected?

I want to get my build files like this

- build
  - button.js
  - button.css
  - index.js
  - components.css

What is actually happening?

It bundles the entire components into one component I use vue-cli-service build --target lib and after that, I get

- build
  - app.2fa32eb.css
  - app.fa24cd4.js

Is it possible to do this with Vue cli, or do I have to use a custom build.

LinusBorg commented 6 years ago

I think right now, you have to call the build command multiple times, for each component you want to create.

This is necessary because we always create a UMD module version of your lib, and these require a name, and each woudl require a different one.

kayandra commented 6 years ago

@LinusBorg thank you, I guess I can write a node script for now. Is there any plan to add this to the builder or will a PR be accepted?

renoirb commented 6 years ago

I'd like to expand a little bit about that topic and making sure the following is what's possible we can do -- or rather how it's designed to be used;

(Also that I didn't find official docs about that use-case, yet)

Assuming, we want a-button, and a-button-two (because it is recommended to use dashes in names) and that we might have more than one form of button.

I'd like to clarify the statement

(...) you have to call the build command multiple times, for each component you want to create.

So, if we have a set of components that share assets (css, mixins, etc), that we maintain in a file tree like this;

- components/
  - button/
    - button.scss
    - button.vue
    - button-two.vue

Assuming each .vue files above has matching {name: 'AButton'} (e.g. for button.vue) in their script tags.

And we want to export for other project usage as ;

- dist/
  - AButton/
    - AButton.umd.js
    - AButton.common.js
  - AButtonTwo/
    - AButtonTwo.umd.js
    - AButtonTwo.common.js
...

We'd have to run;

ASIDE I guess we can't use the same --dest dist/foo for more than one component, because the script might delete the folder (I haven't tested that though)

vue-cli-service build --target lib --name AButton --dest dist/AButton components/button/button.vue
vue-cli-service build --target lib --name AButtonTwo --dest dist/AButtonTwo components/button/button-two.vue

Which makes sense with

This is necessary because we always create a UMD module version of your lib, and these require a name, and each would require a different one.

Did I get that right?

LinusBorg commented 6 years ago

Yep you did.

kayandra commented 6 years ago

@renoirb I'm using the solution you provided above, but I'm building the combination of all the components first. Then you can build the individual components.

Another thing I noticed is that you have to add the / after the folder name in the dest option like this:

yarn build --target lib --name Complete2 --dest dist/complete2/

For the main time, this is what I have working

yarn build --target lib --name components components/main.js

yarn build --target lib --name component1 --dest dist/component1 components/component1.js

I also set dist as main in package.json. So in my application I can require like this

import { Component1 } from 'components'
// or
import Component1 from 'components/component1/component1.common'

The second import format is a bit stressful, so I wrote a little script that runs after building the components. The script iterates the directories and renames any file ending with .common.js into index.js.

divyamrastogi commented 6 years ago

@kayandrae07 : Could you maybe share a GitHub repository for the workaround you've come up with? It would be really helpful for people who might end up referencing this issue even later. Also, this could become a really cool medium article.

mbj36 commented 6 years ago

@kayandrae07 Could you please share the script or may be workaround with a Github repo ? It will be very much helpful..i am bit stuck

wontolla92 commented 6 years ago

How can i remove the demo.html that every build --target lib create? It's usless for an npm component library.

LinusBorg commented 6 years ago

You could add it to .npmignore and forget about it? As an alternative to removing it.

ovgu12 commented 6 years ago

Just keep me follow and i also created https://github.com/ovgu12/vue-lib for demo

adi518 commented 5 years ago

I'm almost certain the reason it does that is because Webpack sees ONE entry point. A library means Webpack has to be configured for multiple entries. This is better, because calling the build command for each component is probably an overkill from a DX perspective. So, to solve this, change the entry configuration from its default (src/main.js) to multiple entries, using vue.config.js. 👍

Webpack expects multiple entries as an object, where each key is the name of the component and its value is the path to the component entry. Normally, you collate all components with a node script and then apply it to the config, but here's a basic example:

// vue.config.js

module.exports = {
  entry = {
    Foo: 'src/components/Foo/index.js', // <component-name>: <component-entry-path>
    Bar: 'src/components/Bar/index.js',
    FooBar: 'src/components/FooBar/index.js'
  }
}

// Usually, I'd have something like this:
// const getComponentsEntries = require('./helpers/getComponentsEntries')
// const entries = getComponentsEntries()
// module.exports = { entry: entries }

It's worth noting the default CLI build might still be more app oriented than library, so it will probably need some more configuration changes, for example no demo.html and no extraction of CSS (but that's opinionated).

I guess we could add an argument to CLI that would allow multiple entries and a library oriented build. 👍

Edit: My bad, looks like it's been taken care of already: https://cli.vuejs.org/guide/build-targets.html#library

amoshydra commented 5 years ago

Updates 2018-12-12

I figured, it is much efficient to configure a webpack with multiple entry instead of spawning 32 node processes.

In the end, I've created a new webpack.config.js to fascilitate this goal. We can still make use of the existing vue-cli's webpack config by merging with @vue/cli-service/webpack.config. Any options can be be modified (such as entry, output) before exporting the config for webpack.

Demo snippet: https://github.com/vuejs/vue-cli/issues/2796#issuecomment-445767979

Build time is 5 seconds for


Original

At the moment I am using a node script to build components in a queue of parallel vue-cli-service build processes. In brief, the script will

  1. glob all relevant vue files in the source folder
  2. Continuously build 12 batches of components in parallel at once by spawning new vue-cli-services build processes
  3. Consolidate different libraryTarget into their respective folders as suggested by https://github.com/vuejs/vue-cli/issues/1065#issuecomment-380690572
    • dist/umd
      • dist/umd/ComponentName/index.js
      • dist/umd/ComponentName/index.map.js
    • dist/umd.min
    • dist/common

In my system, I managed to build 32 components in 35 seconds.

i7-8700 CPU @ 3.20 GHz - 12 Logical processors
16 GB Memory

Example: https://gist.github.com/amoshydra/ab7c33a3ef950e76cceaa1c96d2bf7a0

Benefits:

Challenges:

lalizita commented 4 years ago

I'm trying to build my components as a lib using

vue-cli-service build --target lib --name design-system ./src/components/index.js But my css is not loading with it... How do I build my css inside the js files to load only one file?

adi518 commented 4 years ago

See: https://cli.vuejs.org/config/#css-extract

tommcclean commented 4 years ago

See: https://cli.vuejs.org/config/#css-extract

Doing this in Nuxt seems to give me a document is not defined error; implying the solution breaks SSR