vuejs / vue-loader

📦 Webpack loader for Vue.js components
MIT License
4.99k stars 914 forks source link

15.0.0 support for rules.oneOf config #1204

Closed sqal closed 6 years ago

sqal commented 6 years ago

Version

15.0.0-beta.2

Reproduction link

n/a

Steps to reproduce

Webpack config which should bundle without error:

const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');

const src = path.resolve(__dirname, 'src');

module.exports = {
  entry: {
    app: path.join(src, 'index.js'),
  },
  output: {
    publicPath: '/',
    path: path.join(__dirname, 'build'),
    filename: '[name].bundle.js',
    chunkFilename: '[id].[name].chunk.js',
  },
  module: {
    rules: [{
      oneOf: [
        {
          test: /\.js$/,
          loader: 'babel-loader',
        },
        {
          test: /\.vue$/,
          loader: 'vue-loader',
          options: {
            preserveWhitespace: false,
          },
        },
      ]
    }],
  },
  plugins: [
    new VueLoaderPlugin(),
  ],
};

Webpack version 3.11.0

What is expected?

I would like to bundle my project without error.

What is actually happening?

In my project I use rules.oneOf setup to resolve correct loades (Similar to how create-react-app does it - https://github.com/facebook/create-react-app/blob/next/packages/react-scripts/config/webpack.config.dev.js#L163) but looks like vue-loader cannot handle this configuration correctly and throws this error instead:

TypeError: rawNormalizedRules[i].resource is not a function
    at rawRules.findIndex (C:\dev\vue-loader-next\node_modules\vue-loader\lib\plugin.js:14:53)
    at Array.findIndex (native)
    at VueLoaderPlugin.apply (C:\dev\vue-loader-next\node_modules\vue-loader\lib\plugin.js:13:35)
    at Compiler.apply (C:\dev\vue-loader-next\node_modules\tapable\lib\Tapable.js:375:16)
    at webpack (C:\dev\vue-loader-next\node_modules\webpack\lib\webpack.js:33:19)
    at processOptions (C:\dev\vue-loader-next\node_modules\webpack\bin\webpack.js:335:15)
    at yargs.parse (C:\dev\vue-loader-next\node_modules\webpack\bin\webpack.js:397:2)
    at Object.Yargs.self.parse (C:\dev\vue-loader-next\node_modules\yargs\yargs.js:533:18)
    at Object.<anonymous> (C:\dev\vue-loader-next\node_modules\webpack\bin\webpack.js:152:7)
    at Module._compile (module.js:662:30)
    at Object.Module._extensions..js (module.js:673:10)
    at Module.load (module.js:575:32)
    at tryModuleLoad (module.js:515:12)
    at Function.Module._load (module.js:507:3)
    at Function.Module.runMain (module.js:703:10)
    at startup (bootstrap_node.js:193:16)
    at bootstrap_node.js:665:3
yyx990803 commented 6 years ago

So after 7208885 you should be able to do:

{
  test: /\.vue$/,
  loader: 'vue-loader'
},
{
  oneOf: [
    {
      test: /\.css$/,
      use: ['vue-style-loader', 'css-loader']
    },
    // all other rules
  ]
}

Note the rule for vue-loader must be at the top level, this is required for the plugin to function properly.

Also note in v15, preserveWhitespace has been moved under compilerOptions.preserveWhitespace.

herrdu commented 6 years ago

我花了半天的时间发现 preserveWhitespace 被移动到 compilerOptions.preserveWhitespace 下面了

AlaaHam91 commented 4 years ago

@I have below problem wheni try typing npm run watch

K:\pharma\node_modules\webpack-cli\bin\cli.js:281
                                  @@throw err;
                                ^

Error: [VueLoaderPlugin Error] vue-loader 15 currently does not support vue rules with oneOf.
    at VueLoaderPlugin.apply (K:\pharma\node_modules\vue-loader\lib\plugin-webpack4.js:46:13)
    at webpack (K:\pharma\node_modules\webpack\lib\webpack.js:51:13)
    at processOptions (K:\pharma\node_modules\webpack-cli\bin\cli.js:272:16)
    at K:\pharma\node_modules\webpack-cli\bin\cli.js:364:3
    at Object.parse (K:\pharma\node_modules\webpack-cli\node_modules\yargs\yargs.js:576:18)
    at K:\pharma\node_modules\webpack-cli\bin\cli.js:49:8
    at Object.<anonymous> (K:\pharma\node_modules\webpack-cli\bin\cli.js:366:3)
    at Module._compile (internal/modules/cjs/loader.js:1137:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)
    at Module.require (internal/modules/cjs/loader.js:1025:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (K:\pharma\node_modules\webpack\bin\webpack.js:156:2)
    at Module._compile (internal/modules/cjs/loader.js:1137:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
    at Module.load (internal/modules/cjs/loader.js:985:32)
    at Function.Module._load (internal/modules/cjs/loader.js:878:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
    at internal/main/run_main_module.js:17:47
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ development: `cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the @ development script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Alaa\AppData\Roaming\npm-cache\_logs\2020-07-29T08_00_19_753Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ dev: `npm run development`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Alaa\AppData\Roaming\npm-cache\_logs\2020-07-29T08_00_20_214Z-debug.log

the webpacj.mix.js:


const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')    
    mix.js('resources/js/app.js', 'public/js')
       .sass('resources/sass/app.scss', 'public/css')
       .disableNotifications()
       .webpackConfig({
          plugins: [new VuetifyLoaderPlugin()]
       })
       ;

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": "npm run development -- --watch",
        "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 --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.19",
        "cross-env": "^7.0.2",
        "laravel-mix": "^5.0.1",
        "lodash": "^4.17.13",
        "resolve-url-loader": "^2.3.1",
        "sass": "^1.20.1",
        "sass-loader": "^8.0.0",
        "vue": "^2.5.17",
        "vue-template-compiler": "^2.6.10",
        "vuetify-loader": "^1.6.0",
        "webpack-dev-server": "^3.11.0"
    },
    "dependencies": {
        "@mdi/font": "^5.0.45",
        "@mdi/js": "^5.0.45",
        "ckeditor4-vue": "^1.0.0",
        "laravel-mix-bundle-analyzer": "^1.0.5",
        "moment": "^2.26.0",
        "promise": "^8.1.0",
        "qs": "^6.9.4",
        "vue-i18n": "^8.18.1",
        "vue-mq": "^1.0.1",
        "vue-notification": "^1.3.20",
        "vue-router": "^3.1.6",
        "vuelidate": "^0.7.5",
        "vuetify": "^2.3.6",
        "vuex": "^3.3.0",
        "xlsx": "^0.16.0"
    }
}

I have project (Laravel with vue.js)downloaded from Gitlab and after i installed the dependencies (npm install & composer install), i can not compile it,as when i try typing: npm run watch, i got below error:

K:\pharma\node_modules\webpack-cli\bin\cli.js:281 throw err; ^

Error: [VueLoaderPlugin Error] vue-loader 15 currently does not support vue rules with oneOf. at VueLoaderPlugin.apply (K:\pharma\node_modules\vue-loader\lib\plugin-webpack4.js:46:13) at webpack (K:\pharma\node_modules\webpack\lib\webpack.js:51:13) at processOptions (K:\pharma\node_modules\webpack-cli\bin\cli.js:272:16) at K:\pharma\node_modules\webpack-cli\bin\cli.js:364:3 at Object.parse (K:\pharma\node_modules\webpack-cli\node_modules\yargs\yargs.js:576:18) at K:\pharma\node_modules\webpack-cli\bin\cli.js:49:8 at Object. (K:\pharma\node_modules\webpack-cli\bin\cli.js:366:3) at Module._compile (internal/modules/cjs/loader.js:1137:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10) at Module.load (internal/modules/cjs/loader.js:985:32) at Function.Module._load (internal/modules/cjs/loader.js:878:14) at Module.require (internal/modules/cjs/loader.js:1025:19) at require (internal/modules/cjs/helpers.js:72:18) at Object. (K:\pharma\node_modules\webpack\bin\webpack.js:156:2) at Module._compile (internal/modules/cjs/loader.js:1137:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10) at Module.load (internal/modules/cjs/loader.js:985:32) at Function.Module._load (internal/modules/cjs/loader.js:878:14) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12) at internal/main/run_main_module.js:17:47 npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! @ development: cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the @ development script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\Alaa\AppData\Roaming\npm-cache_logs\2020-07-29T08_00_19_753Z-debug.log npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! @ dev: npm run development npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the @ dev script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\Alaa\AppData\Roaming\npm-cache_logs\2020-07-29T08_00_20_214Z-debug.log the webpacj.mix.js:

const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')
mix.js('resources/js/app.js', 'public/js') .sass('resources/sass/app.scss', 'public/css') .disableNotifications() .webpackConfig({ plugins: [new VuetifyLoaderPlugin()] }) ; if i comment below codes,the npm run watch can compile the project.

.webpackConfig({ plugins: [new VuetifyLoaderPlugin()] }) 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": "npm run development -- --watch", "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 --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { "axios": "^0.19", "cross-env": "^7.0.2", "laravel-mix": "^5.0.1", "lodash": "^4.17.13", "resolve-url-loader": "^2.3.1", "sass": "^1.20.1", "sass-loader": "^8.0.0", "vue": "^2.5.17", "vue-template-compiler": "^2.6.10", "vuetify-loader": "^1.6.0", "webpack-dev-server": "^3.11.0" }, "dependencies": { "@mdi/font": "^5.0.45", "@mdi/js": "^5.0.45", "ckeditor4-vue": "^1.0.0", "laravel-mix-bundle-analyzer": "^1.0.5", "moment": "^2.26.0", "promise": "^8.1.0", "qs": "^6.9.4", "vue-i18n": "^8.18.1", "vue-mq": "^1.0.1", "vue-notification": "^1.3.20", "vue-router": "^3.1.6", "vuelidate": "^0.7.5", "vuetify": "^2.3.6", "vuex": "^3.3.0", "xlsx": "^0.16.0" } } log file:

0 info it worked if it ends with ok 1 verbose cli [ 1 verbose cli 'C:\Program Files\nodejs\node.exe', 1 verbose cli 'C:\Users\Alaa\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js', 1 verbose cli 'run', 1 verbose cli 'dev' 1 verbose cli ] 2 info using npm@6.14.7 3 info using node@v12.18.3 4 verbose run-script [ 'predev', 'dev', 'postdev' ] 5 info lifecycle @~predev: @ 6 info lifecycle @~dev: @ 7 verbose lifecycle @~dev: unsafe-perm in lifecycle true 8 verbose lifecycle @~dev: PATH: C:\Users\Alaa\AppData\Roaming\npm\node_modules\npm\node_modules\npm-lifecycle\node-gyp-bin;K:\pharma\node_modules.bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;C:\Program Files\Microsoft\Web Platform Installer\;C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\xampp\php;C:\composer;C:\Program Files\dotnet\;C:\Program Files\Microsoft DNX\Dnvm\;C:\Program Files\Git\cmd;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Yarn\bin\;C:\Program Files\nodejs\;C:\xampp\php;C:\Users\Alaa\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\Alaa\AppData\Roaming\Composer\vendor\bin;C:\xampp\php;C:\Program Files\nodejs;C:\Users\Alaa.dotnet\tools;C:\Users\Alaa\AppData\Local\Yarn\bin;C:\Users\Alaa\AppData\Roaming\npm 9 verbose lifecycle @~dev: CWD: K:\pharma 10 silly lifecycle @~dev: Args: [ '/d /s /c', 'npm run development' ] 11 silly lifecycle @~dev: Returned: code: 1 signal: null 12 info lifecycle @~dev: Failed to exec dev script 13 verbose stack Error: @ dev: npm run development 13 verbose stack Exit status 1 13 verbose stack at EventEmitter. (C:\Users\Alaa\AppData\Roaming\npm\node_modules\npm\node_modules\npm-lifecycle\index.js:332:16) 13 verbose stack at EventEmitter.emit (events.js:315:20) 13 verbose stack at ChildProcess. (C:\Users\Alaa\AppData\Roaming\npm\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14) 13 verbose stack at ChildProcess.emit (events.js:315:20) 13 verbose stack at maybeClose (internal/child_process.js:1021:16) 13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:286:5) 14 verbose pkgid @ 15 verbose cwd K:\pharma 16 verbose Windows_NT 10.0.18362 17 verbose argv "C:\Program Files\nodejs\node.exe" "C:\Users\Alaa\AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js" "run" "dev" 18 verbose node v12.18.3 19 verbose npm v6.14.7 20 error code ELIFECYCLE 21 error errno 1 22 error @ dev: npm run development 22 error Exit status 1 23 error Failed at the @ dev script. 23 error This is probably not a problem with npm. There is likely additional logging output above. 24 verbose exit [ 1, true ]

vuetify-loader/lib/plugin.js:

const RuleSet = require('webpack/lib/RuleSet')
const progressiveLoaderModule = require('../progressive-loader/module')
let vueLoaderPath
try {
  vueLoaderPath = require.resolve('vue-loader')
} catch (err) {}

function isVueLoader (use) {
  return use.ident === 'vue-loader-options' ||
    use.loader === 'vue-loader' ||
    (vueLoaderPath && use.loader === vueLoaderPath)
}

class VuetifyLoaderPlugin {
  constructor (options) {
    this.options = options || {}
  }

  apply (compiler) {
    // use webpack's RuleSet utility to normalize user rules
    const rawRules = compiler.options.module.rules
    const { rules } = new RuleSet(rawRules)
    this.rules = rules

    // find the rules that apply to vue files
    const vueRules = rules.filter(rule => rule.use && rule.use.find(isVueLoader))

    if (!vueRules.length) {
      throw new Error(
        `[VuetifyLoaderPlugin Error] No matching rule for vue-loader found.\n` +
        `Make sure there is at least one root-level rule that uses vue-loader.`
      )
    }

    vueRules.forEach(this.updateRule.bind(this))

    compiler.options.module.rules = rules
  }

  updateRule (rule) {
    if (this.options.progressiveImages) {
      const vueLoaderOptions = rule.use.find(isVueLoader).options
      vueLoaderOptions.compilerOptions = vueLoaderOptions.compilerOptions || {}
      vueLoaderOptions.compilerOptions.modules = vueLoaderOptions.compilerOptions.modules || []
      vueLoaderOptions.compilerOptions.modules.push(progressiveLoaderModule)

      const imageRuleIndex = this.rules.findIndex(rule => {
        return rule.resource &&
          !rule.resourceQuery &&
          ['.png', '.jpg', '.jpeg', '.gif'].some(ext => rule.resource(ext))
      })
      let imageRule = this.rules[imageRuleIndex]

      const options = typeof this.options.progressiveImages === 'boolean'
        ? undefined
        : this.options.progressiveImages

      if (!imageRule) {
        imageRule = {
          test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)(\?.*)?$/,
          oneOf: [
            {
              test: /\.(png|jpe?g|gif)$/,
              resourceQuery: options ? options.resourceQuery : /vuetify-preload/,
              use: [
                {
                  loader: 'vuetify-loader/progressive-loader',
                  options
                },
                {
                  loader: 'url-loader',
                  options: { limit: 8000 }
                }
              ]
            },
            {
              loader: 'url-loader',
              options: { limit: 8000 }
            }
          ]
        }
        rules.push(imageRule)
      } else {
        if (Array.isArray(imageRule.use)) {
          imageRule.oneOf = [
            {
              test: /\.(png|jpe?g|gif)$/,
              resourceQuery: options ? options.resourceQuery : /vuetify-preload/,
              use: [
                {
                  loader: 'vuetify-loader/progressive-loader',
                  options
                },
                ...imageRule.use
              ]
            },
            ...imageRule.use
          ]
        } else if (imageRule.loader) {
          imageRule.oneOf = [
            {
              test: /\.(png|jpe?g|gif)$/,
              resourceQuery: options ? options.resourceQuery : /vuetify-preload/,
              use: [
                {
                  loader: 'vuetify-loader/progressive-loader',
                  options
                },
                {
                  loader: imageRule.loader,
                  options: imageRule.options
                }
              ]
            },
            {
              loader: imageRule.loader,
              options: imageRule.options
            }
          ]
        }
        delete imageRule.use
        delete imageRule.loader
        delete imageRule.options
      }
    }

    rule.oneOf = [
      {
        resourceQuery: '?',
        use: rule.use
      },
      {
        use: [
          {
            loader: require.resolve('./loader'),
            options: {
              match: this.options.match || [],
              attrsMatch: this.options.attrsMatch || []
            }
          },
          ...rule.use
        ]
      },
    ]
    delete rule.use
  }
}

module.exports = VuetifyLoaderPlugin

@yyx990803

gottayan commented 2 years ago

@yyx990803 could you solve this problem to support the oneof function of webpack?

wangyapeng commented 1 year ago

can the 'vue-style-loader' repeate the style-loader?