Import a Vue js component from Laravel Blade File

前端 未结 3 1619
甜味超标
甜味超标 2021-02-04 22:39

I have registered a some components as a global components in js/app.js file, But this makes the compiled app.js file larger.

//example         


        
相关标签:
3条回答
  • 2021-02-04 23:06

    register the component in another file rather than app.js

    resources/js/example.js

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

    Compile your component to another file in 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');
    

    Include it in blade

    <script src="/js/example.js"></script>
    
    0 讨论(0)
  • 2021-02-04 23:13

    As like Caddy DZ answered it's the way to go with laravel-mix. (CaddyDz happen to be my close friend by the way hhhh)

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

    Multi pages, multi bundles! laravel-mix-glob is the answer

    However if there is multi pages. And keeping doing it that way. It's a bit of hassle. Or not the coolest of the ways. For this purpose i developed a pakage laravel-mix-glob. Which is a wrapper around laravel-mix. That do some magic for you.

    Which allow you to use globs and have all the files that get added automatically handled for you. In place of managing them file by file. Page by page.

    The use is so simple. You can check the package here:

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

    The documentation explain everything. You have to check the portion about the compileSpecifier

    You can give it a one read. And then you'll be more productive. And the magic just happen. Even everything is explained within the doc even how laravel-mix-glob work.

    You can also check this issue. Which show some nice points:

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

    And to clear things even just here. Here a use example:

    // 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
    
    

    Some notes

    For the bellow

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

    It translate to take all the js or jsm files in the directory resources/js/ or any of it's sub directories at all levels. And that are not part of resources/js/secondPattern/**/*. And output them in public/js. Holding the same structure from the base resources/js/. Whenever you add a new file that respect that structure it will be automatically compiled for you (well laravel-mix watcher will be restarted and with it the whole build). And you don't have to do it file by file. At all.

    For instance let say at start you have 6 files that match the patterns. laravel-mix-glob automatically will make all the 6 right calls. And then even when you add new file it know automatically and recompile.

    And laravel-mix-glob leverage all the best glob patterns. In the most intuitive way. Going from simple to the most complex. And the people used to use the glob libraries. Gulp. Or many other tools. Will just find it too familiar. Everything is simple. And it's all explained in the doc. There is many examples too.

    compileSpecifier

    It's an important feature. Imaging you want to bundle only few files from many. Adding the specifier and having the feature to be automatically managed and stripped from the output is just interesting and effective. That's the motivation. By default is activated you can deactivated as shown in the example bellow.

    Final words

    Check the doc as it's more complete and tackle all the different parts. The package was been there for months now. And it was well tested in Linux. More less in windows. But many users of both platform used it. And it work perfectly and magically. To give you more comfort and allow you to be more productive.

    Also as the author i'm too open to the community. I review and handle PR with great joy. And i like to have contributors. So any interested one can let me know. Here or by filling an issue.

    0 讨论(0)
  • 2021-02-04 23:30

    To further extend on Salim Example, you can add Vue to the window and directly create the exported Vue Component within the Vue File.


      1. Autoload Vue Within Laravel Mix
      1. Globally Register Component As You Create Them
      1. Instead Of Requiring Each Component, Simplify With Laravel Mix
      1. Extend Laravel Mix, removing every import, require, register, & compile step - simply create a vue component and use it

    1) Autload Vue Within Laravel Mix


    webpack.mix.js

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

    2) Register Vue Components Globally As You Create Them


    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) Instead of requiring each component simply use 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) Simplify Further By 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. Extend Laravel Mix Removing All Extra Steps

    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();
    }
    
    0 讨论(0)
提交回复
热议问题