2

I have a vue client project that uses a vue library project (the vue library project is also using some 3rd party packages like vue-material).

They are linked via the client project's Package.json like this "lib": "file:../lib" and I am importing components in the client project using import Comp from "lib/src/components/Comp";

The problem is that when I build the client project using Webpack, the files in my library use lib/node_modules/vue instead of node_modules/vue which causes double vue instancing.

Anyone has any idea why when I am using webpack build from the client folder, it looks for vue package in my library folder? and is there a way to get around that?

My webpack.config

"use strict";
const path = require("path");
const utils = require("./utils");
const config = require("../config");
const vueLoaderConfig = require("./vue-loader.conf");

function resolve(dir) {
  return path.join(__dirname, "..", dir);
}

module.exports = {
  entry: {
    app: ["babel-polyfill", "./src/main.js"]
  },
  output: {
    path: config.build.assetsRoot,
    filename: "[name].js",
    publicPath: process.env.NODE_ENV === "production" ? config.build.assetsPublicPath : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: [".js", ".vue", ".json"],
    alias: {
      vue$: "vue/dist/vue.esm.js",
      "@": resolve("src"),
      src: resolve("src"),
      assets: resolve("src/assets"),
      components: resolve("src/components"),
      utilities: resolve("src/utilities"),
      directives: resolve("src/directives"),
      plugins: resolve("src/plugins"),
      data: resolve("src/data"),
      "vuex-store": resolve("src/store"),
      "lib": resolve("node_modules/lib")
    }
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: "eslint-loader",
        enforce: "pre",
        include: [resolve("src")],
        options: {
          formatter: require("eslint-friendly-formatter")
        }
      },
      {
        test: /\.vue$/,
        loader: "vue-loader",
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        include: [resolve("src"), resolve("../lib/src")]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: "url-loader",
        options: {
          limit: 10000,
          name: utils.assetsPath("img/[name].[hash:7].[ext]")
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: "url-loader",
        options: {
          limit: 10000,
          name: utils.assetsPath("media/[name].[hash:7].[ext]")
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: "base64-font-loader",
        options: {
          limit: 10000,
          name: utils.assetsPath("fonts/[name].[hash:7].[ext]")
        }
      },
      {
        test: /\.ico$/,
        loader: "file-loader?name=[name].[ext]"
      }
    ]
  }
};

My client's main entry

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

// Core Imports
import Vue from 'vue'
import App from './App'

// Plugins
import { ComponentsPlugin } from "lib/src/components";

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})
3
  • Can you post the webpack.config.js and the relevant code where you use the import ? Commented Oct 20, 2019 at 21:48
  • Alright, I posted my config files Commented Oct 21, 2019 at 1:01
  • I think this line "lib": resolve("node_modules/lib") on your webpack.config.sj cause the problem. I don't know the vue library (yours ? 3rd party ?) Suggestion: a. If yours move the lib into your src and remove the lib alias b. Add and index.js into the node_modules\lib folder with the require("src/components") Commented Oct 21, 2019 at 7:39

1 Answer 1

3

As I ran out of solutions to this problem I decided to debug webpack's compiler.

It seems webpack uses a library called 'enhanced-resolve' (We actually send parameters to that library in our webpack's resolve:{} section). And using the resolve.alias property we can redirect any require to any folder we want.

So to redirect any require("vue") to my own vue.esm.js, all I need is to add an entry like this (I originally had that line but it was pointing to a relative path rather than an absolute path):

resolve: {
  alias: {
    vue$: resolve("node_modules/vue/dist/vue.esm.js"),
  }
}

Note the $ at the end of the library name, It signals enhanced-resolve that the package only has 1 module so any require whos name is "vue" or a sub-directory of "vue" should be parsed using the alias.

Enhanced-Resolve - ResolverFactory.js

if(/\$$/.test(alias)) {
    onlyModule = true;
    ....
}

Enhanced-Resolve - AliasPlugin.js

// InnerRequest is the path (vue/dist/vue.esm.js)
// name is the alias name without the $ (vue)
if(innerRequest === name || (!onlyModule && startsWith(innerRequest, name + "/"))) {
    continue resolving....
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.