background

In the article “Three Methods for Common Components of Front-end Multiple VUE Projects (Recommended introduction of NPM File)”, the method of NPM introducing public packages through file is discussed, but there will be many pits in practical application. Here are two problems encountered by the author and the solutions are given.

Problem a

NPM does not automatically install dependencies for packages imported through file. For example, project A imports package B in file mode, as shown below. Package. json in project A:

{
  "name": "A"."version": "0.1.0 from"."dependencies": {
    "B": "file:.. /B"
  }
  / /...
}
Copy the code

Package. json for project B:

{
  "name": "B"."version": "0.1.0 from"."dependencies": {
    "axios": "^ 0.19.2"
  }
  / /...
}
Copy the code

So when NPM install is executed in project A, the AXIOS package is not installed, and there is only one B in node_modules that is introduced via A soft link.

The solution

Main ideas:

  • Add a WebPack plugin, DepPlugin, and execute the plugin after the entryOption hook, just after WebPack has processed the configuration item.
  • Read all dependencies in the package.json file in dependencies. Read all dependencies in the NPM package in dependencies.
  • Install all dependencies above at once, executeNPM install [email protected] [email protected] [email protected] --no-save(A, B, and c are the names of dependency packages).

Here is the code: vue.config.js

chainWebpack: config= > {
  const depPlugin = require('./plugin/DepPlugin')
  config.plugin('DepPlugin').use(depPlugin).tap(args= > args)
}
Copy the code

DepPlugin.js

'use strict'
const path = require('path')
const sep = path.sep
let cwd = process.cwd()
const execSync = require('child_process').execSync

function DepPlugin (options) {
  this.options = options || {}
  this.done = false
}
DepPlugin.prototype.apply = function (compiler) {
  const that = this
  compiler.hooks.entryOption.tap('DepPlugin'.compiler= > {
    if(that.done) return
    const mainDependency = getDependency('. ' + sep + 'package.json')
    // Suppose file introduces two items, baqi and Baqi-chat
    letsubDependency = { ... getSubDependency('baqi'),
      ...getSubDependency('baqi-chat')}const subDependencyKey = Object.keys(subDependency)
    const mainDependencyKey = Object.keys(mainDependency)
    // Get the dependencies in the current package
    // Look for dependencies in baqi, baqi-chat, but not in the main package
    for (let i = 0; i < subDependencyKey.length; i++) {
      if (mainDependencyKey.includes(subDependencyKey[i])) {
        delete subDependency[subDependencyKey[i]]
      }
    }
    // Install these dependencies
    execCmdSync('cd ' + cwd)
    let str = ' '
    for (let dep in subDependency) {
      // install node_modules without these packages
      if (fs.existsSync(path.join(cwd, 'node_modules' + sep + dep)) === false) {
        str += dep + The '@' + subDependency[dep].replace(/\"|\^|\~/g.' ') + ' '}}if (str) {
      execCmdSync('npm install ' + str + '--no-save')}}}function getSubDependency (moduleName) {
  const filePath = path.join(cwd, '.. ' + sep + moduleName + sep + 'package.json')
  const dependencies = getDependency(filePath)
  return dependencies
}
function getDependency (packageJsonPath) {
  const fileObj = JSON.parse(readPackageJson(packageJsonPath))
  const dependency = fileObj.dependencies
  return dependency
}
function readPackageJson (packageJsonPath) {
  const fileStr = fs.readFileSync(packageJsonPath, 'utf8')
  return fileStr
}
function execCmdSync (cmdStr) {
  console.log('Execute:' + cmdStr)
  const out = execSync(cmdStr, { encoding: 'utf8' })
  return out
}
Copy the code

Question 2

Babel does not automatically escape packages imported by file, which means that subpackages with ES6 writing in them will report an error when running in older browsers.

The solution

The vUE website describes it this waySo, you can add it in vue.config.js

transpileDependencies: [ 
  /[/\\]node_modules[/\\]baqi[/\\]/./[/\\]node_modules[/\\]baqi-chat[/\\]/
]
Copy the code

The same problem applies to the NPM link