web-dev-qa-db-fra.com

vue-loader 15 avec laravel-mix

J'essaie donc de mettre à jour mon projet vue-loader dans le projet laravel vers la version 15.2.1. Après la mise à jour des dépendances et l'exécution de npm run watch, je reçois d'abord une erreur signalant que je devrais utiliser VueLoaderPlugin. Je l'ai ajouté comme le suggère la documentation officielle.
Après avoir essayé d’exécuter à nouveau la commande de construction, j’obtiens cette erreur pour chacun de mes composants: 

    ERROR in ./node_modules/css-loader!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/lib/loader.js!./node_modules/vue-loader/lib??vue-loader-options!./resources/assets/js/components/users/User.vue?vue&type=style&index=0&id=d0ee1f54&scoped=true&lang=sass
Module build failed:
<template lang="pug">
^
      Invalid CSS after "": expected 1 selector or at-rule, was ".user-container"
      in C:\MAMP\htdocs\lightCRM\resources\assets\js\components\users\User.vue (line 1, column 1)
 @ ./node_modules/style-loader!./node_modules/css-loader!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/lib/loader.js!./node_modules/vue-loader/lib??vue-loader-options!./resources/assets/js/components/users/User.vue?vue&type=style&index=0&id=d0ee1f54&scoped=true&lang=sass 4:14-338
 @ ./resources/assets/js/components/users/User.vue?vue&type=style&index=0&id=d0ee1f54&scoped=true&lang=sass
 @ ./resources/assets/js/components/users/User.vue
 @ ./resources/assets/js/routes/routes.js
 @ ./resources/assets/js/app.js
 @ multi ./resources/assets/js/app.js

Si iam ajoute cette règle à ma configuration laravel-mix 

rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]

Ensuite, la compilation fonctionne avec succès, mais dans la console, je reçois:

[vue warn]: failed to mount component: template or render function not defined.  

J'utilise sass et pug dans mes composants vue avec des chargeurs appropriés. Ajouter plus de règles à laravel-mix config semble ne faire aucune différence. Toutes les dépendances sont à jour et fonctionnent bien avec vue-loader v.14.2.2. La version de Node.js est 10.1.0 et npm est 6.1.0.
Voici aussi mon package.json: 

    {
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.18.0",
        "babel-core": "^6.26.3",
        "babel-loader": "^7.1.4",
        "babel-plugin-transform-runtime": "^6.23.0",
        "babel-preset-es2015": "^6.24.1",
        "cross-env": "^5.1.6",
        "css-loader": "^0.28.11",
        "laravel-mix": "2.1",
        "lodash": "^4.17.10",
        "node-sass": "^4.9.0",
        "pug": "^2.0.3",
        "pug-loader": "^2.4.0",
        "pug-plain-loader": "^1.0.0",
        "sass-loader": "^7.0.1",
        "sass-resources-loader": "^1.3.3",
        "vue": "^2.5.16",
        "vue-html-loader": "^1.2.4",
        "vue-loader": "^15.2.1",
        "vue-style-loader": "^4.1.0"
    },
    "dependencies": {
        "es6-promise": "^4.2.4",
        "vue-multiselect": "^2.1.0",
        "vue-router": "^3.0.1",
        "vuex": "^3.0.1"
    }
}  

Voici la déclaration de résolution de WebpackConfig.js 

buildResolving() {
    this.webpackConfig.resolve = {
        extensions: ['*', '.js', '.jsx', '.vue'],

        alias: {
            vue$: 'vue/dist/vue.common.js'
        }
    };

    return this;
}  

Et voici tous mes webpack.mix.js 

    mix.js('resources/assets/js/app.js', 'public/js')
   .copy('resources/assets/fonts/', 'public/fonts/')
   .webpackConfig({
     plugins: [
       new VueLoaderPlugin()
     ],
     resolve: {
       alias: {
         'Global': path.resolve('resources/assets/sass')
       }
     }
   })

Je l'ai fonctionne bien. Voici un projet de bibliothèque utilisant laravel mix avec Vue Loader 15 - https://github.com/niiknow/vue-datatables-net

Je n'ai pas de projet public Laravel à démontrer, mais voici mon package de projet privé.json

{
    "private": true,
    "scripts": {
        "clean": "rm -rf ./public/js/parts/*",
        "dev": "npm run development",
        "development": "npm run clean && cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run clean && cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "npm run clean && cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "npm run clean && cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "test": "npm run clean && cross-env NODE_ENV=test mocha-webpack --webpack-config=node_modules/laravel-mix/setup/webpack.config.js --require tests/Vue/setup.js tests/Vue/**/*.spec.js",
        "watch-test": "npm run clean && cross-env NODE_ENV=test mocha-webpack --webpack-config=node_modules/laravel-mix/setup/webpack.config.js --watch --require tests/Vue/setup.js tests/Vue/**/*.spec.js",
        "lint": "eslint --ext .js,.vue resources/js",
        "lint-fix": "eslint --fix --ext .js,.vue resources/js",
        "check-outdated": "npm outdated"
    },
    "devDependencies": {
        "autotrack": "^2.4.1",
        "axios": "^0.18.0",
        "axios-jsonp": "^1.0.2",
        "babel-core": "^6.26.3",
        "babel-eslint": "^10.0.1",
        "babel-loader": "^7.1.5",
        "babel-plugin-transform-imports": "^1.5.1",
        "babel-polyfill": "^6.26.0",
        "babel-preset-vue-app": "^2.0.0",
        "bootstrap": "^4.1.3",
        "bootstrap-vue": "^2.0.0-rc.11",
        "browser-sync": "^2.26.0",
        "browser-sync-webpack-plugin": "^2.0.1",
        "cross-env": "^5.1.6",
        "datatables.net-bs4": "^1.10.19",
        "datatables.net-buttons-bs4": "^1.5.4",
        "datatables.net-fixedheader-bs4": "^3.1.5",
        "datatables.net-responsive-bs4": "^2.2.3",
        "eslint": "^5.9.0",
        "eslint-config-prettier": "^3.3.0",
        "eslint-friendly-formatter": "^4.0.1",
        "eslint-loader": "^2.1.0",
        "eslint-plugin-vue": "^5.0.0-beta.4",
        "inputmask": "^4.0.3",
        "jQuery-QueryBuilder": "^2.5.2",
        "jquery": "^3.3.1",
        "laravel-mix": "^2.1.14",
        "lodash": "^4.17.11",
        "noty": "^3.2.0-beta",
        "popper.js": "^1.14.5",
        "sweetalert2": "^7.29.0",
        "tinycolor2": "^1.4.1",
        "vee-validate": "2.1.2",
        "vform": "^1.0.0",
        "vue": "^2.5.17",
        "vue-authenticate": "^1.3.4",
        "vue-axios": "^2.0.2",
        "vue-datatables-net": "^1.0.1",
        "vue-element-loading": "^1.0.5",
        "vue-i18n": "^8.3.1",
        "vue-loader": "^15.4.2",
        "vue-router": "^3.0.1",
        "vue-template-compiler": "^2.5.17",
        "vue2-google-maps": "^0.10.2",
        "vuedraggable": "^2.16.0",
        "vuex": "^3.0.1",
        "vuex-persistedstate": "^2.5.4",
        "vuex-router-sync": "^5.0.0"
    },
    "dependencies": {},
    "browserslist": [
        "> 1%",
        "last 2 versions",
        "not ie <= 9"
    ],
    "engines": {
        "node": ">= 8.10.x",
        "npm": ">= 5.6.0"
    }
}

Et voici mon webpack.mix.js

const path = require('path');
const mix = require('laravel-mix');
const { VueLoaderPlugin } = require('vue-loader');
const source = 'resources';
const public = 'public';

mix.options({
  processCssUrls: false,
  uglify: {
    uglifyOptions: {
      compress: {
        drop_console: true
      }
    }
  }
});

mix.setPublicPath(path.normalize(public));

mix.webpackConfig({
  externals: {
    'jquery': 'jQuery'
  },
  output: { chunkFilename: 'js/parts/[name].js' },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(vue|js)$/,
        exclude: /(node_modules|bower_components)/,
        loader: 'eslint-loader',
        options: {
          fix: false,
          cache: false,
          formatter: require('eslint-friendly-formatter')
        }
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin()
  ],
  devServer: { overlay: true },
  devtool: 'source-map',
  resolve: {
    /* Path Shortcuts */
    alias:{
      /* root */
      '~': path.resolve(__dirname, `${ source }/js`),
      Components: path.resolve(__dirname, `${ source }/js/components`),
      Layouts: path.resolve(__dirname, `${ source }/js/layouts`),
      Pages: path.resolve(__dirname, `${ source }/js/pages`)
    }
  }
});

mix.js(`${ source }/js/myapp.js`, `${ public }/js`);
mix.sass(`${ source }/sass/myapp.scss`, `${ public }/css`, {
  outputStyle: mix.inProduction() ? 'compact' : 'expanded'
});
mix.sourceMaps();
mix.browserSync({
  proxy: 'yourproject.test',
  Host: 'yourproject.test',
  files: [
    `${ source }/views/**/*.php`,
    `${ public }/js/**/*.js`,
    `${ public }/css/**/*.css`
  ],
  browser: 'firefox',
  ghostMode: false,
  open: 'external'
});

mix.extract([
  'autotrack',
  'axios',
  'axios-jsonp',
  'noty',
  'popper.js',
  'sweetalert2',
  'tinycolor2',
  'vee-validate',
  'vform',
  'vue',
  'vue-authenticate',
  'vue-axios',
  'vue-element-loading',
  'vue-i18n',
  'vue-router',
  'vue2-google-maps',
  'vuedraggable',
  'vuex',
  'vuex-persistedstate',
  'vuex-router-sync'
]);

if (mix.inProduction()) {
  mix.version();
  mix.disableNotifications();
}

Et voici mon .babelrc

{
    "presets":
    [
        [
            "env",
            {
                "targets": {
                    "browsers": ["last 2 versions"]
                },
                "debug": true,
                "useBuiltIns": "entry"
            }
        ]
    ],
    "plugins": ["transform-runtime", "syntax-dynamic-import"]
}

Voici .eslint.js

module.exports = {
  root: true,
  env: {
    browser: true,
  },
  plugins: ['vue'], // enable vue plugin
  extends: ["plugin:vue/recommended", "prettier"], // activate vue related rules
  parserOptions: {
    "parser": "babel-eslint",
    "ecmaVersion": 7,
    "sourceType": "module",
    "ecmaFeatures": {
      "globalReturn": false,
      "impliedStrict": false,
      "jsx": false,
      "experimentalObjectRestSpread": false,
      "allowImportExportEverywhere": false
    }
  },
  rules: {
    // allow paren-less arrow functions
    "arrow-parens": 0,
    // allow async-await
    "generator-star-spacing": 0,
    // allow debugger during development
    "no-debugger": process.env.NODE_ENV === 'production' ? 2 : 0,
    "semi": [2, "never"],
    "quotes": [2, "single"],
    "vue/require-default-prop": 0,
    "vue/require-prop-types": 0,
    "vue/no-v-html": 0
  }
};

1
Noogen