【问题标题】:Include importable modules from outside project folder for webpack HMR Vue.js为 webpack HMR Vue.js 包含来自外部项目文件夹的可导入模块
【发布时间】:2019-01-09 14:29:37
【问题描述】:

我的项目结构如下:

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

【问题讨论】:

    标签: webpack vue.js webpack-hmr


    【解决方案1】:
    • 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' 守护程序并发出我所做的更改。

    希望有帮助!

    【讨论】:

      【解决方案2】:

      在类似的情况下,我使用 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:shared1 与别名 @s1

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

      优点:无需额外设置,在浏览器中一切正常,在控制台中没有警告/错误,您可以在 VSCode 工作区中轻松打开 shared1 作为附加文件夹,因此您可以编辑所有 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 来解决此问题,确保它在尝试以“常规”方式查找​​之前首先检查主目录的 node_modules,但它似乎没有帮助。

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

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

      优点:Intellisense 有效,不再出现构建错误。

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

      尝试 3:shared3 与别名 @s3

      代码方面,尝试 3 与尝试 1 没有太大区别,但使用一个简单的技巧,一切都按我的意愿进行。诀窍是使用 symlink,我使用了一个名为 symlink-dir 的多平台 npm 包来轻松完成此操作。我实际上已将它作为开发依赖项添加到 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,但我仍然对这个最终结果非常满意,因为它非常适合我们这个小团队。

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

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

      【讨论】:

        【解决方案3】:

        **** 更新****

        所以这有点像地狱。对我来说,这种设置是小团队 (1-4) 的理想设置。如果您已经有一个包含子项目的父 repo(单体),您不想处理 npm 打包或创建额外的 repo。您希望能够直接在项目中开发和调试组件。比更新、打包、吸进另一个包要快得多。我终于在使用 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 或使用 bit (https://bitsrc.io) 。所有这些解决方案似乎都比上述解决方案更笨重,更不顺畅。

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            【解决方案5】:

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

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

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

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

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

            这应该就是你所需要的。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-01-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-01-17
              • 2021-03-07
              相关资源
              最近更新 更多