包括来自Webpack HMR Vue.js的外部项目文件夹中的可导入模块

时间:2018-08-01 22:29:37

标签: webpack vue.js webpack-hmr

我的项目结构如下:

.
+-- 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时的路径问题,但在浏览器中调试时却无法解决。任何帮助表示赞赏。希望已经建立了类似项目结构的人能有所启发!

4 个答案:

答案 0 :(得分:2)

我在类似情况下使用Terra的解决方案已经有一段时间了,这很好,但是对我来说有一个缺点,即如果共享代码也需要它们自己的node_modules内容,那么intellisense不起作用,何时即使在浏览器中一切正常,构建项目时,也会出现错误(找不到模块...)。也许是因为我正在使用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的shared1

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

专业人士:无需其他设置,所有功能都可在浏览器中正常运行,控制台中无警告/错误,您可以在VSCode工作空间中轻松地将shared1作为其他文件夹打开,因此您可以编辑所有shared1文件。

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

尝试2:别名为@ s2的shared2

要尝试修复它,我已将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来解决此问题,确保在尝试查找“常规”方式之前先检查主目录的node_modules,但这似乎无济于事。

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

也许有人有办法正确地解决它?

专家:Intellisense可以正常工作,不再有构建错误。

缺点:运行时错误,没有可用的应用程序,以及额外的复杂性/风险,因为必须使模块在project1 / shared2之间保持相同的版本号,才能使intellisense始终如一地工作。

尝试3:使用别名@ s3的shared3

在代码方面,尝试3与尝试1并没有什么不同,但是使用一个简单的技巧,一切都会按照我的要求进行。诀窍是使用 symlink ,我使用了一个名为symlink-dir的多平台npm软件包来轻松实现此目的。实际上,我已经将它作为dev依赖项添加到project1的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,但我对最终结果仍然感到非常满意,因为它对于我们作为一个小型团队而言非常理想。

专家:没有警告,错误等:一切都像代码在项目中一样工作(这种情况是正确的),同时在其他项目中仍然可以访问该代码。

缺点:每个开发人员都需要手动创建符号链接,然后代码才能编译/使用intellisense。再说一次,他们还必须为此运行npm install。

答案 1 :(得分:0)

****更新****

所以这有点地狱。对我来说,此设置是小团队(1-4)的理想设置。如果您已经有一个带有子项目的父仓库(整体式),则您不想处理npm打包或创建其他仓库。您希望能够直接在项目中开发和调试组件。这比更新,打包和吸入另一个程序包要快得多。最终,除了使用了Common文件夹中组件的项目上的webpack HMR之外,其他所有东西都正常工作。这就是对我有用的东西:

添加到上面的webpack.config.js解决:

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

在解析(webpack.config.js)中为Common文件夹添加别名:

'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 repo的根目录。

替代方案使用NPM或使用位(https://bitsrc.io)。所有这些解决方案似乎都比上面的解决方案笨拙且没有摩擦。

答案 2 :(得分:0)

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

今晚我遇到了类似情况,我想将一些自定义库移出到外部共享lib目录中,以进行敏捷开发和模拟测试。我大约在两周前才开始学习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'

现在,如果我编辑任何项目或( external )个lib文件,则webpack HMR将启动并刷新正在运行的“ yarn serve”守护程序,并发出我所做的更改。

希望有帮助!

答案 3 :(得分:0)

删除node_modules内部的package文件夹,并创建一个指向node_modules内部实际项目的符号链接。

rm -rf my_project/node_modules/shared_lib

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