为 webpack HMR 包含来自外部项目文件夹的可导入模块 Vue.js

Include importable modules from outside project folder for webpack HMR Vue.js

我的项目结构如下:

.
+-- Common
|   +-- MyCommonVueComponent.Vue
+-- MainProject
|   +-- webpack.config.js
|   +-- package.json
|   +-- node_modules
|   +-- src

当我从控制台构建时,webpack 不会抱怨,因为它似乎具有从 Common 导入到 MainProject 的组件的 node_modules 文件夹的正确路径。当我尝试在浏览器中调试 Vue.js 应用程序时,出现以下错误:

../Common/MyCommonVueComponent.Vue
Module not found: Error: Can't resolve 'vue-hot-reload-api' in 'D:\Projects\Cb\CommonVue'

我添加了:

resolveLoader: {
        modules: [path.resolve(__dirname, './node_modules')],
    },

这似乎确实解决了 运行 webpack 在控制台中的路径问题,但在浏览器中调试时却没有。任何帮助表示赞赏。希望设置了类似项目结构的人可以阐明一些问题!

**** 更新 ****

所以这有点糟糕。对我而言,此设置是小型团队 (1-4) 的理想设置。如果您已经有一个包含子项目的父仓库(单体),您不想处理 npm 打包或创建额外的仓库。您希望能够直接在您的项目中开发和调试组件。比更新、打包、吸入另一个包要快得多。除了 webpack HMR 之外,我终于在使用 Common 文件夹中的组件的项目上完成了所有工作。这是最终为我工作的东西:

添加到 webpack.config.js 以上解析:

resolveLoader: {
    modules: [path.resolve(__dirname, 'node_modules')],
},

为 Common 文件夹在 resolve (webpack.config.js) 中添加一个别名:

'Common': path.resolve(__dirname, '../Common') <- this is the root of my mono repo

修改我在 webpack.config.js 中的输出(添加 publicPath):

output: {
        path: path.join(__dirname, bundleOutputDir),
        filename: '[name].js',
        publicPath: 'dist/'
    },

到目前为止这似乎有效。这让我可以直接将 .Vue 组件文件放在一个名为 Common 的文件夹中,该文件夹是我所有其他项目文件的同级文件。所有项目包括主解决方案文件夹中的公共站点,该文件夹是我的 git 存储库的根目录。

备选方案是使用 NPM 或使用 bit (https://bitsrc.io)。所有这些解决方案似乎都比上述解决方案更笨重、更顺畅。

  • Vue-cli: v3.11.0
  • webpack: v4.40.2
  • 巴别塔:7.6.0
  • 节点:v10.16.3

今晚我 运行 遇到了类似的情况,我想将一些自定义库移出到外部共享库目录中,以进行敏捷开发和模拟测试。我大约两周前才开始学习 Vue/webpack 生态系统,我可以肯定地说这是一次冒险,因为 webpack 是一个令人生畏的野兽,它找出了所有必须正确对齐的神秘旋钮和按钮。

./devel  (webpack alias: TTlib)
+-- lib
|   +-- widget.js
|   +-- frobinator.js
|   +-- suckolux3000.js
+-- share (suckolux3000.js taps into this directory)
|   +-- imgs
|   +-- icons
|   |   +-- img
|   |   +-- svg
+-- MainProject
|   +-- vue.config.js
|   +-- package.json
|   +-- node_modules
|   +-- src
+-- TestProject
|   +-- vue.config.js
|   +-- package.json
|   +-- node_modules
|   +-- src

我关心的是确保 webpack HMR 能够正常工作,我可以说你已经很接近了,但还不够深入。幸运的是,修复非常简单。

这是我的 vue.config.js 添加内容:

module.exports = {
  configureWebpack: {
    resolve: {
      alias: {
        'TTlib': '/devel/lib'
      },
      modules: ['/devel/lib']
    },
    resolveLoader: {
      modules: ['/devel/lib']
    }
  }
};

现在,在我的任何 *Project 组件中,我可以使用:

import frobinator from 'TTlib/frobinator'

现在,如果我编辑任何项目或(外部)lib 文件,webpack HMR 将启动并刷新 运行 'yarn serve' 守护进程和发出我所做的更改。

希望对您有所帮助!

我在类似情况下使用 Terra 的解决方案有一段时间了,效果很好,但对我来说有一个缺点,即如果共享代码也需要 node_modules 他们自己的内容,那么智能感知没有工作,在构建项目时,即使在浏览器中一切正常,也会出现错误(找不到模块...)。也许是因为我使用的是 TypeScript?无论哪种方式,使用单独的包或像 bit 这样的高级工具似乎都太麻烦了,所以我去寻找一个没有缺点的更简单的解决方案。

我已经将我的尝试放在这个存储库中:https://github.com/brease-colin/vue-typescript-shared 那里有一个项目文件夹 (project1) 和三个共享文件夹尝试,它们都同时链接到 project1 中,都有自己的缺点),但我打算使用尝试 3,因为它对我们来说并不是真正的缺点。

顺便说一句,这三个问题都有一个共同点,但也许那是我的 VSCode 行为怪异。如果在 VSCode 中打开根文件夹,则 Vue 文件中的 Intellisense 无法理解这三个解决方案中的任何一个导入,而如果在 VSCode 中打开 project1 文件夹,它会理解所有三个的导入。下面对每次尝试的描述都假定在 VSCode.

中打开 project1

要查看的主要文件是:

  • project1/src/components/HelloWorld.vue : 尝试重用共享组合函数和共享组件的 vue 文件
  • project1/src/data/ProjectDummies.ts : 尝试重用共享 ts 文件的 ts 文件
  • project1/tsconfig.json
  • project1/vue.config.js
  • shared[1/2/3]/components/Header[1/2/3].vue : 从@vue/composition-api.
  • 导入的共享组件

尝试 1:使用别名 @s1 共享 1

这是 Terra 答案的 Typescript 版本。我只向 tsconfig 文件添加了一个路径和两个包含路径,以使智能感知工作。还要查看 shared1/tsconfig.json,因为我在那里添加了相同的别名 (@s1),所以共享文件之间的引用很顺利。

优点:无需额外设置,在浏览器中一切正常,控制台中没有警告/错误,您可以轻松打开 shared1 作为 [=112= 中的附加文件夹] 工作区,因此您可以编辑所有 shared1 文件。

缺点:对 node_modules 的引用在 VSCode 中不起作用,并且在终端中也会输出错误。因此,在您的项目文件夹中使用 类 时,没有智能感知/没有类型安全。最后一部分对我来说是个大骗局。

尝试 2:shared2 别名@s2

为了尝试修复它,我在共享文件夹中添加了一个 package.json 并为共享文件安装了所需的包(在本例中为:@vue/composition-api)。这使得智能感知工作并且构建时的终端输出错误也消失了。但是,现在代码在 运行 时间在浏览器中出现故障,因为添加了两次依赖项并且共享文件夹中的导入不引用相同的模块代码。这不会在所有类型的依赖项中产生错误,但在某些情况下,一些常量会被初始化,这些常量在整个代码库中应该是相同的。我得到的错误是:

[Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().

[Vue warn]: Error in data(): "Error: [vue-composition-api] must call Vue.use(VueCompositionAPI) before using any function."

found in

---> <Header2> at shared2/components/Header2.vue
   <HelloWorld> at src/components/HelloWorld.vue
     <Home> at src/views/Home.vue
       <App> at src/App.vue
         <Root>

我尝试通过更改模块 resolve / resolveLoader 来解决这个问题,确保它在尝试查看 'regular' 方式之前首先检查主目录的 node_modules,但它没有似乎有帮助。

modules: [
  path.resolve(__dirname, 'node_modules'),
  'node_modules',
],

也许有人有办法正确修复它?

优点:智能感知有效,不再出现构建错误。

缺点:运行时错误,没有可用的应用程序,加上额外的复杂性/风险,因为必须使模块在 project1 / shared2 之间保持相同的版本号以保持智能感知一致工作。

尝试 3:shared3 别名@s3

代码方面,尝试 3 与尝试 1 没有太大区别,但使用一个简单的技巧,一切都按我想要的方式进行。诀窍是使用 symlink 并且我使用了一个名为 symlink-dir 的多平台 npm 包来轻松做到这一点。我实际上已经将它作为开发依赖项添加到项目 1 的 package.json:

npm install --save-dev symlink-dir

之后,我制作了如下符号链接,每次克隆存储库时都必须这样做。

npx symlink-dir ../shared3/ shared3/

现在,为了防止两次签入代码,您必须在 .gitignore 中添加一行:

// .gitignore
*/shared3/

因为共享代码现在在您的项目文件夹中,您甚至可以在没有别名的情况下访问它,但是为了更容易地让共享文件夹中的文件相互访问,我更喜欢固定别名,所以我添加了它将以下配置添加到 vue.config.js 和 tsconfig.json:

// vue.config.js
configureWebpack: {
  resolve: {
    alias: {
      '@s3': path.resolve(__dirname, 'shared3'),
    },
  }
},

// tsconfig.json
"compilerOptions": {
  // only needed for auto completion(?)
  "paths": {
    "@s3/*": ["shared3/*"],
  },
},

虽然我更喜欢仅配置解决方案来改进 shared1,但我仍然对最终结果感到非常满意,因为它非常适合我们这个小团队。

优点:没有警告、错误等:一切都像代码在项目中一样工作,情况就是这样,同时仍然可以访问代码其他项目。

缺点:每个开发人员都需要在他们的代码编译/使用智能感知之前手动创建符号链接。然后,他们还必须 运行 npm install 为此。

删除node_modules里面的package文件夹,在node_modules里面创建一个符号link到真正的项目。

rm -rf my_project/node_modules/shared_lib

ln -s /path/shared_lib my_project/node_modules/shared_lib

来自 ASP.NET 开发,我们使用类似的设置,这是我们在 JavaScript 开发环境中寻找的项目结构。我们在尝试大量 baseurl/paths/alias 组合时遇到了所有相同的问题,所有这些组合都导致某种失败的 es-linting、打字稿处理、模块加载或其他。

最终对我们有用的解决方案其实很简单。

我们使用符号 links 映射到公共项目文件夹中。以管理员身份添加符号 link 运行 CMD 并执行 mklink /D "C:\SymbolicLink\To" "C:\Actual\Common\Directory"

完成此操作后,您需要更改 vue.config.js 文件中的一项关键设置。如果没有此设置,依赖项将从它们的实际位置而不是符号 link 位置解析。

configureWebpack: {
    resolve: {
      symlinks: false // Dependencies must be resolvable from the symlinked location, not the real location
    }
}

这应该就是您所需要的。