Packaging Vue Components for npm

    By packaging your component to be shared via npm, it can be imported/required into a build process for use in full-fledged web applications:

    Or even used via tag in the browser directly:

    1. <script src="https://unpkg.com/vue"></script>
    2. <script src="https://unpkg.com/my-component"></script>
    3. ...
    4. <my-component></my-component>
    5. ...

    Not only does this help you avoid copy/pasting components around, but it also allows you to give back to the Vue community!

    Can’t I Just Share .vue Files Directly?

    Vue already allows components to be written as a single file. Because a Single File Component (SFC) is already just one file, you might ask:

    It’s true, you can share .vue files directly, and anyone using a containing the Vue compiler can consume it immediately. Also, the SSR build uses string concatenation as an optimization, so the .vue file might be preferred in this scenario (see Packaging Components for npm > SSR Usage for details). However, this excludes anyone who wishes to use the component directly in a browser via <script> tag, anyone who uses a runtime-only build, or build processes which don’t understand what to do with .vue files.

    Properly packaging your SFC for distribution via npm enables your component to be shared in a way which is ready to use everywhere!

    For the purposes of this section, assume the following file structure:

    1. package.json
    2. build/
    3. rollup.config.js
    4. src/
    5. wrapper.js
    6. dist/

    The package.json file used by npm really only requires one version (main), but as it turns out, we aren’t limited to that. We can address the most common use cases by specifying 2 additional versions (module and unpkg), and provide access to the .vue file itself using the browser field. A sample package.json would look like this:

    When webpack 2+, Rollup, or other modern build tools are used, they will pick up on the module build. Legacy applications would use the main build, and the unpkg build can be used directly in browsers. In fact, the cdn automatically uses this when someone enters the URL for your module into their service!

    SSR Usage

    You might have noticed something interesting - browsers aren’t going to be using the browser version. That’s because this field is actually intended to allow authors to provide hints to bundlers which in turn create their own packages for client side use. With a little creativity, this field allows us to map an alias to the .vue file itself. For example:

    1. import MyComponent from 'my-component/sfc'; // Note the '/sfc'

    Compatible bundlers see the browser definition in package.json and translate requests for into my-component/src/my-component.vue, resulting in the original .vue file being used instead. Now the SSR process can use the string concatenation optimizations it needs to for a boost in performance.

    Note: When using .vue components directly, pay attention to any type of pre-processing required by script and style tags. These dependencies will be passed on to users. Consider providing ‘plain’ SFCs to keep things as light as possible.

    There is no need to write your module multiple times. It is possible to prepare all 3 versions of your module in one step, in a matter of seconds. The example here uses due to its minimal configuration, but similar configuration is possible with other build tools - more details on this decision can be found here. The package.json scripts section can be updated with a single entry for each build target, and a more generic build script that runs them all in one pass. The sample package.json file now looks like this:

    1. {
    2. "name": "my-component",
    3. "version": "1.2.3",
    4. "main": "dist/my-component.umd.js",
    5. "module": "dist/my-component.esm.js",
    6. "unpkg": "dist/my-component.min.js",
    7. "browser": {
    8. "./sfc": "src/my-component.vue"
    9. },
    10. "scripts": {
    11. "build": "npm run build:umd & npm run build:es & npm run build:unpkg",
    12. "build:umd": "rollup --config build/rollup.config.js --format umd --file dist/my-component.umd.js",
    13. "build:es": "rollup --config build/rollup.config.js --format es --file dist/my-component.esm.js",
    14. "build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/my-component.min.js"
    15. },
    16. "devDependencies": {
    17. "rollup": "^1.17.0",
    18. "rollup-plugin-buble": "^0.19.8",
    19. "rollup-plugin-commonjs": "^10.0.1",
    20. "rollup-plugin-vue": "^5.0.1",
    21. "vue-template-compiler": "^2.6.10"
    22. },
    23. ...
    24. }

    Remember, if you have an existing package.json file, it will likely contain a lot more than this one does. This merely illustrates a starting point. Also, the packages listed in devDependencies (not their versions) are the minimum requirements for rollup to create the three separate builds (umd, es, and unpkg) mentioned. As newer versions become available, they should be updated as necessary.

    Our changes to package.json are complete. Next, we need a small wrapper to export/auto-install the actual SFC, plus a minimal Rollup configuration, and we’re set!

    What does my packaged component look like?

    Notice the first line directly imports your SFC, and the last line exports it unchanged. As indicated by the comments in the rest of the code, the wrapper provides an install function for Vue, then attempts to detect Vue and automatically install the component. With 90% of the work done, it’s time to sprint to the finish!

    With the package.json scripts section ready and the SFC wrapper in place, all that is left is to ensure Rollup is properly configured. Fortunately, this can be done with a small 16 line rollup.config.js file:

    1. import commonjs from 'rollup-plugin-commonjs'; // Convert CommonJS modules to ES6
    2. import vue from 'rollup-plugin-vue'; // Handle .vue SFC files
    3. import buble from 'rollup-plugin-buble'; // Transpile/polyfill with reasonable browser support
    4. export default {
    5. input: 'src/wrapper.js', // Path relative to package.json
    6. output: {
    7. name: 'MyComponent',
    8. exports: 'named',
    9. },
    10. plugins: [
    11. commonjs(),
    12. vue({
    13. css: true, // Dynamically inject css as a <style> tag
    14. compileTemplate: true, // Explicitly convert template to render function
    15. }),
    16. buble(), // Transpile to ES5
    17. ],

    This sample config file contains the minimum settings to package your SFC for npm. There is room for customization, such as extracting CSS to a separate file, using a CSS preprocessor, uglifying the JS output, etc.

    Also, it is worth noting the name given the component here. This is a PascalCase name that the component will be given, and should correspond with the kebab-case name used elsewhere throughout this recipe.

    Will this replace my current development process?

    The configuration here is not meant to replace the development process that you currently use. If you currently have a webpack setup with hot module reloading (HMR), keep using it! If you’re starting from scratch, feel free to install , which will give you the whole HMR experience config free:

    1. vue serve --open src/my-component.vue

    In other words, do all of your development in whatever way you are comfortable. The things outlined in this recipe are more like ‘finishing touches’ than a full dev process.

    When to Avoid this Pattern

    Packaging SFCs in this manner might not be a good idea in certain scenarios. This recipe doesn’t go into detail on how the components themselves are written. Some components might provide side effects like directives, or extend other libraries with additional functionality. In those cases, you will need to evaluate whether or not the changes required to this recipe are too extensive.

    In addition, pay attention to any dependencies that your SFC might have. For example, if you require a third party library for sorting or communication with an API, Rollup might roll those packages into the final code if not properly configured. To continue using this recipe, you would need to configure Rollup to exclude those files from the output, then update your documentation to inform your users about these dependencies.

    Acknowledgements

    This recipe is the result of a lightning talk given by Mike Dodge at VueConf.us in March 2018. He has published a utility to npm which will quickly scaffold a sample SFC using this recipe. You can download the utility, , from npm. You can also clone the repo and customize it.