【问题标题】:Import a Vue js component from Laravel Blade File从 Laravel Blade 文件中导入一个 Vue js 组件
【发布时间】:2020-01-27 00:26:12
【问题描述】:

我在js/app.js文件中注册了一些组件作为全局组件,但这使得编译后的app.js文件变大了。

//example: app.js
Vue.component('profile-page', require('./components/profiles/ProfilePage.vue').default);

问题是:有没有办法在 laravel-blade 文件中导入任何这些全局组件,而不是在 app.js 文件中全局注册?

类似这样的:

// laravel-blade file
<script>
    import ProfilePage from ...;
</script>

【问题讨论】:

    标签: laravel vue.js laravel-blade


    【解决方案1】:

    在另一个文件中注册组件而不是app.js

    resources/js/example.js

    window.Vue = require('vue');
    Vue.component('example-component', require('./components/ExampleComponent.vue').default);
    

    将你的组件编译到webpack.mix.js中的另一个文件

    mix.js('resources/js/app.js', 'public/js')
       .js('resources/js/example.js', 'public/js')
       .sass('resources/sass/app.scss', 'public/css');
    

    将其包含在刀片中

    <script src="/js/example.js"></script>
    

    【讨论】:

    • 就是这样,谢谢
    【解决方案2】:

    就像 Caddy DZ 回答的那样,这是使用 laravel-mix 的方式。 (顺便说一句,CaddyDz 正好是我的好朋友 hhhh)

    https://stackoverflow.com/a/58122158/7668448

    多页,多包! laravel-mix-glob 就是答案

    但是如果有多页。并继续这样做。这有点麻烦。或者不是最酷的方式。为此,我开发了一个包laravel-mix-glob。这是一个围绕 laravel-mix 的包装器。这对你有一些魔力。

    这允许您使用 globs 并自动为您处理所有添加的文件。代替逐个文件管理它们。一页一页。

    使用非常简单。你可以在这里查看包裹:

    https://www.npmjs.com/package/laravel-mix-glob

    文档解释了一切。您必须检查有关 compileSpecifier

    的部分

    你可以读一读。然后你会更有效率。魔法就这样发生了。甚至所有内容都在文档中进行了解释,甚至 laravel-mix-glob 是如何工作的。

    您也可以检查此问题。其中显示了一些不错的观点:

    https://github.com/MohamedLamineAllal/laravel-mix-glob/issues/5#issuecomment-537991979

    即使就在这里,也要把事情清理干净。这里是一个使用示例:

    // imports
    const mix = require('laravel-mix'); // you need the laravel mix instance
    const MixGlob = require('laravel-mix-glob');
    
    // init
    const mixGlob = new MixGlob({mix}); // mix is required
    // or 
    const mixGlob = new MixGlob({
        mix, // mix required
        mapping: { // optional
            // see the doc
        },
        // more options maybe added in future version (fill issues if you need anything, or a PR if you like)
    });
    
    
    // use mixGlob
    mixGlob.sass('resources/sass/**/*.compile.scss', 'public/css', null, {
        base: 'resources/sass/',
        // compileSpecifier: { 
        //     disabled: true // there is no compile specifier (disabled), and so it will not be removed from the extension (by default disabled = false, and the default specifier = 'compile', and it get removed from the path)
        //      ,
        //      specifier: 'cmp'
        // }
        // mapping: {   // this take precedency over any other mapping // useless feature as laravel-mix doesn't support output in different formats. (until i find a workaround)
        //     ext: {
        //         'scss': 'css' // multiple files separatly
        //     },
            // or
            // ext: 'css', // all to the same
            //   
        // }
    })
    .js(['resources/js/**/*.compile.{js,jsm}', '!resources/js/secondPattern/**/*'], 'public/js/', null, {
        base: 'resources/js/'
    }) // multiple globs pattern as an array. Also with exclusion support (!)
    .js('resources/js/secondPattern/**/*.compile.{js,jsm}', 'public/js', null, {
        base: 'resources/js/secondPattern'
    })
    .ts(['resources/js/ts/**/*.compile.ts', 'resources/js/tsx/**/*.compile.tsx'], 'public/js', null, {
        base: {
            ts: 'resources/js/ts/', // per file extension  mapping
            tsx: 'resources/js/tsx/**/*.compile.tsx'
        }
    })
    .mix('sass')('resources/sass/summernote.scss', '../resources/views/system/admin/dashboard/partials/_summernote_css.blade.php'); // laravel-mix instance
    
    

    一些注意事项

    为了下面

    .js(['resources/js/**/*.compile.{js,jsm}', '!resources/js/secondPattern/**/*'], 'public/js/', null, {
        base: 'resources/js/'
    })
    

    它转换为获取目录resources/js/ 或其任何各级子目录中的所有jsjsm 文件。这不是resources/js/secondPattern/**/* 的一部分。并将它们输出到public/js。从基础resources/js/ 保持相同的结构。每当您添加一个尊重该结构的新文件时,它都会自动为您编译(laravel-mix watcher 将重新启动并伴随整个构建)。而且您不必逐个文件地执行此操作。完全没有。

    例如,假设在开始时您有 6 个与模式匹配的文件。 laravel-mix-glob 会自动进行所有 6 次正确的调用。然后即使您添加新文件,它也会自动知道并重新编译。

    laravel-mix-glob 利用了所有最好的 glob 模式。以最直观的方式。从简单到最复杂。人们过去常常使用 glob 库。吞咽。或许多其他工具。只会觉得太熟悉了。一切都很简单。这一切都在文档中进行了解释。也有很多例子。

    编译说明符

    这是一个重要的功能。成像您只想捆绑多个文件中的几个文件。添加说明符并从输出中自动管理和剥离功能非常有趣且有效。这就是动机。默认情况下是激活的,你可以按照下面的例子去激活。

    最后的话

    检查文档,因为它更完整并解决了所有不同的部分。这个包裹已经在那里好几个月了。它在 Linux 中经过了很好的测试。在 Windows 中更少。但是这两个平台的许多用户都使用了它。它完美而神奇地工作。让您更加舒适并提高工作效率。

    作为作者,我对社区也很开放。我非常高兴地审查和处理公关。我喜欢有贡献者。所以有兴趣的可以告诉我。在这里或通过填写问题。

    【讨论】:

      【解决方案3】:

      为了进一步扩展 Salim 示例,您可以将 Vue 添加到窗口中,并直接在 Vue 文件中创建导出的 Vue 组件。



      1) 在 Laravel Mix 中自动加载 Vue


      webpack.mix.js

      const mix = require('laravel-mix');
      
      mix.autoload({vue: ['Vue', 'window.Vue']})
         .js(...)
         .css(...)
         .version()
      

      2) 在创建 Vue 组件时全局注册它们


      resources/js/components/profile/profile-image.vue

      <template>
          <div class='profile-image' @click='show(user)'>
              <img :src='user.avatar' :alt='`${user.name} profile image`' />
          </div>
      </template>
      
      <script>
        /** Note: Global Component Registered Via Vue.component(...) **/
      
        Vue.component('profile-image', {   
           props: ['user'],
      
           methods: {
              /** 
               * Show User Profile Page
               */
               show(user) {
                  const { location } = window;
      
                  window.location = `${location.origin}/users/${user.id}`;
               }
            }
         });
      </script>
      

      3) 不需要每个组件,只需使用Laravel Mix

      webpack.mix.js

      const mix = require('laravel-mix');
      
      mix.autoload({ 
        vue: [
           'Vue', 
           'window.Vue'
        ] 
      })
      .js([
            /* --------------------------------- 
             |   Card Components
             | ---------------------------------
             |
             | . Card.vue (Original)
             | . IconCard.vue (Topic Contextually Relevant Icon)
             | . DetailCard.vue (Shown On Detail Pages & Used To Summarize Index Tables)
             |
            */
            'resources/js/components/cards/card.vue',
            'resources/js/components/cards/icon-card.vue',
            'resources/js/components/cards/index-card.vue',
            'resources/js/components/cards/detail-card.vue',
            'resources/js/components/cards/organization-card.vue',
      
            /* --------------------------------- 
             |   Button Components
             | ---------------------------------
             |
             | . Button.vue (Original)
             | . ButtonRipple.vue (Interactive Click Effects)
             | . ButtonFabIcon.vue (Rounded, Material Design Icons)
             |
            */
            'resources/js/components/buttons/button.vue',
            'resources/js/components/buttons/primary.vue',
            'resources/js/components/buttons/success.vue',
            'resources/js/components/buttons/button-ripple.vue',
            'resources/js/components/buttons/primary-ripple.vue',
            'resources/js/components/buttons/success-ripple.vue',
            'resources/js/components/buttons/button-fab-icon.vue',
            'resources/js/components/buttons/primary-fab-icon.vue',
            'resources/js/components/buttons/success-fab-icon.vue',
      
      
      
            /* --------------------------------- 
             |   Fields Components
             | ---------------------------------
             |
             | . Form.vue (Create & Update)
             | . Detail.vue (Show, Edit, & Cards)
             | . Index.vue (Tables Ex: Sort, Search, Filter)
             |
            */
            'resources/js/components/fields/date/form.vue',
            'resources/js/components/fields/date/index.vue',
            'resources/js/components/fields/date/detail.vue',
      
            /** Then that one component we actually created ;D **/
            'resources/js/components/profile/profile-image.vue',
      
      ], 'resources/js/components/bootstrap.js')
      
      
      .babel([
            /* ------------------------------------------------------------------
             | Mounting Vue & Using "Babel" (Vanilla JS For Every Browsers)  
             | ------------------------------------------------------------------
             |
             | . Our Components are compiled
             | . Our Last File Being Added Will Mount Vue
             | . We'll Use ".babel()" While Adding This File
             | . "Babel" Simply Transforms All Javascript Into Vanilla JS
             |
            */
              'resources/js/components/bootstrap.js', 
              'resources/js/bootstrap/mount-vue.js'
      
      ], 'public/js/app.js')
      
      
      /*------------------------------*/
      /* Optimization Minification   
      /*------------------------------*/
      .minify('public/js/app.js');
      
      /*------------------------------*/
      /* Cache Busting Versioning   
      /*------------------------------*/
      if (mix.inProduction()) {
        mix.version();
      }
      

      4) 进一步简化 Extending Laravel Mix

      resources/js/mix-extensions/mix-every-vue-component.js

      import upperFirst from 'lodash/upperFirst'
      import camelCase from 'lodash/camelCase'
      
      const requireComponent = require.context(
        // The relative path of the components folder
        './components',
        // Whether or not to look in subfolders
        false,
        // The regular expression used to match base component filenames
        /Base[A-Z]\w+\.(vue|js)$/
      )
      
      requireComponent.keys().forEach(fileName => {
        // Get component config
        const componentConfig = requireComponent(fileName)
      
        // Get PascalCase name of component
        const componentName = upperFirst(
          camelCase(
            // Gets the file name regardless of folder depth
            fileName
              .split('/')
              .pop()
              .replace(/\.\w+$/, '')
          )
        )
      
      
        // Register component globally
        Vue.component(
          componentName,
          // Look for the component options on `.default`, which will
          // exist if the component was exported with `export default`,
          // otherwise fall back to module's root.
          componentConfig.default || componentConfig
        )
      })
      

      webpack.mix.js

      const mix = require('laravel-mix');
      
      class LaravelMixEveryVueComponent
      {
          public constructor() {
      
          }
      
      }
      mix.autoload({ 
        vue: [
           'Vue', 
           'window.Vue'
        ] 
      })
      .js([
            /* --------------------------------- 
             |   Card Components
             | ---------------------------------
             |
             | . Card.vue (Original)
             | . IconCard.vue (Topic Contextually Relevant Icon)
             | . DetailCard.vue (Shown On Detail Pages & Used To Summarize Index Tables)
             |
            */
            'resources/js/components/cards/card.vue',
            'resources/js/components/cards/icon-card.vue',
            'resources/js/components/cards/index-card.vue',
            'resources/js/components/cards/detail-card.vue',
            'resources/js/components/cards/organization-card.vue',
      
            /* --------------------------------- 
             |   Button Components
             | ---------------------------------
             |
             | . Button.vue (Original)
             | . ButtonRipple.vue (Interactive Click Effects)
             | . ButtonFabIcon.vue (Rounded, Material Design Icons)
             |
            */
            'resources/js/components/buttons/button.vue',
            'resources/js/components/buttons/primary.vue',
            'resources/js/components/buttons/success.vue',
            'resources/js/components/buttons/button-ripple.vue',
            'resources/js/components/buttons/primary-ripple.vue',
            'resources/js/components/buttons/success-ripple.vue',
            'resources/js/components/buttons/button-fab-icon.vue',
            'resources/js/components/buttons/primary-fab-icon.vue',
            'resources/js/components/buttons/success-fab-icon.vue',
      
      
      
            /* --------------------------------- 
             |   Fields Components
             | ---------------------------------
             |
             | . Form.vue (Create & Update)
             | . Detail.vue (Show, Edit, & Cards)
             | . Index.vue (Tables Ex: Sort, Search, Filter)
             |
            */
            'resources/js/components/fields/date/form.vue',
            'resources/js/components/fields/date/index.vue',
            'resources/js/components/fields/date/detail.vue',
      
            /** Then that one component we actually created ;D **/
            'resources/js/components/profile/profile-image.vue',
      
      ], 'resources/js/components/bootstrap.js')
      
      
      .babel([
            /* ------------------------------------------------------------------
             | Mounting Vue & Using "Babel" (Vanilla JS For Every Browsers)  
             | ------------------------------------------------------------------
             |
             | . Our Components are compiled
             | . Our Last File Being Added Will Mount Vue
             | . We'll Use ".babel()" While Adding This File
             | . "Babel" Simply Transforms All Javascript Into Vanilla JS
             |
            */
              'resources/js/components/bootstrap.js', 
              'resources/js/bootstrap/mount-vue.js'
      
      ], 'public/js/app.js')
      
      
      /*------------------------------*/
      /* Optimization Minification   
      /*------------------------------*/
      .minify('public/js/app.js');
      
      /*------------------------------*/
      /* Cache Busting Versioning   
      /*------------------------------*/
      if (mix.inProduction()) {
        mix.version();
      }
      

      4. 扩展 Laravel Mix 删除所有额外步骤

      laravel-mix-autoload-vuejs-extension.js

      const mix = require('laravel-mix');
      
      
      const CollectFiles = (folder, files = []) => {
          const isFolder = to => File(path.resolve(to)).isDirectory();
          const CombineFiles = (Files, Segments = []) => [ ...files, path.join(__dirname, Segments[0], '/', Segments[1])];
      
          return fs.readdirSync(folder).reduce((filed, file) =>
                  isFolder(`${folder}/${file}`)
                      ? CollectFiles(`${folder}/${file}`, files)
                      : CombineFiles(files, [folder, file]),
              files
          ).map(string => string.replace(__dirname, ''));
      };
      
      
      class LaravelMixAutoloadVue
      {
          constructor()
          {
              this.LoadVueComponents = (to, output) => mix.js(CollectFiles(to), output);
      
              return mix;
          }
      
          dependencies()
          {
              return ['fs', 'path'];
          }
      
          name()
          {
              return ['vuejs'];
          }
      
          register(to, output)
          {
              if (typeof to === 'undefined') {
                  return console.log(`Output is undefined for codesplit path ${to}`);
              }
      
              this.LoadVueComponents(to, output);
          }
      
          boot()
          {
              console.log("Booting Example");
          }
      }
      
      mix.extend('vuejs', new LaravelMixAutoloadVue());
      
      

      webpack.mix.js webpack.mix.js

      const mix = require('laravel-mix');
      require('./laravel-mix-autoload-vuejs`);
      
      mix.autoload({ 
        vue: [
           'Vue', 
           'window.Vue'
        ] 
      })
            /* -------------------------------------------------------------
             |  Laravel Mix Autoload Vue Extensions Handles All Components
             | -------------------------------------------------------------
            */
      .vuejs('resources/js/components/', 'resources/js/components/bootstrap.js') 
      .babel([
            /* ------------------------------------------------------------------
             | Mounting Vue & Using "Babel" (Vanilla JS For Every Browsers)  
             | ------------------------------------------------------------------
             |
             | . Our Components are compiled
             | . Our Last File Being Added Will Mount Vue
             | . We'll Use ".babel()" While Adding This File
             | . "Babel" Simply Transforms All Javascript Into Vanilla JS
             |
            */
              'resources/js/components/bootstrap.js', 
              'resources/js/bootstrap/mount-vue.js'
      
      ], 'public/js/app.js')
      
      
      /*------------------------------*/
      /* Optimization Minification   
      /*------------------------------*/
      .minify('public/js/app.js');
      
      /*------------------------------*/
      /* Cache Busting Versioning   
      /*------------------------------*/
      if (mix.inProduction()) {
        mix.version();
      }
      

      【讨论】:

        猜你喜欢
        • 2020-04-20
        • 2019-10-04
        • 2020-02-18
        • 2022-11-11
        • 2020-07-23
        • 2021-04-10
        • 2018-04-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多