Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Path must be a string. Received undefined (4.0.2 + webpack 2.1.0-beta.23 + ?sourceMap) #285

Closed
mstawick opened this issue Sep 20, 2016 · 23 comments

Comments

@mstawick
Copy link

sass-loader 4.0.2 + webpack 2.1.0-beta.23 + ?sourceMap

TypeError: Path must be a string. Received undefined
at assertPath (path.js:7:11)
at Object.relative (path.js:1228:5)
at Object.onRender (/node_modules/sass-loader/index.js

this.options.context is undefined

Problem goes away if I remove ?sourceMap from loader.

@wellyshen
Copy link

I have the same issue +1

@phairoh
Copy link

phairoh commented Sep 20, 2016

Ignore my deleted comment. I was incorrect.

@phairoh
Copy link

phairoh commented Sep 20, 2016

This seems to fix the issue:

new webpack.LoaderOptionsPlugin({
    options: {
        sassLoader: {
            includePaths: [path.resolve(__dirname, 'src', 'scss')]
        },
        context: '/'
    }
})

Looking at the code in the DllReferencePlugin it looks like there is a new way to get the context.

@borysn
Copy link

borysn commented Oct 5, 2016

@phairoh I'm running into a similar issue, I'd love to get your opinion, just not sure where to go from here. It could be a simple configuration issue, but maybe the loaders I'm using need updates.

I'm loading bootstrap sass files using bootstrap-loader and sass-loader, which leads to an error...

 69% building modules 1180/1181 modules 1 active ...ode_modules/bootstrap-loader/no-op.jsTypeError: Path must be a string. Received undefined
    at assertPath (path.js:8:11)
    at Object.posix.relative (path.js:495:3)
    at Object.onRender (/home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/sass-loader/index.js:282:42)
    at /home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/sass-loader/node_modules/async/dist/async.js:2231:35
    at arrayEach (/home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/sass-loader/node_modules/async/dist/async.js:1357:13)
    at Object.<anonymous> (/home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/sass-loader/node_modules/async/dist/async.js:2223:17)
    at Object.<anonymous> (/home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/sass-loader/node_modules/async/dist/async.js:338:31)
    at Object.callback (/home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/sass-loader/node_modules/async/dist/async.js:847:20)
    at options.success (/home/p3pt/dev/java/projects/spring-boot-angular2/frontend/node_modules/node-sass/lib/index.js:309:32)

The stack trace starts at bootstrap-loader, but most of it stems from sass-loader. Looking above at your solution, I tried adding something like...

...
        new webpack.LoaderOptionsPlugin({
          options: {
            postcss: [autoprefixer],

            sassLoader: {
              includePaths: [helpers.root('node_modules/bootstrap/scss')]
            },

            context: __dirname,
          }
        })
...

but this did not resolve the issue for me. Again, not sure if the actual issue is bootstrap-loader, sass-loader, or just missing configuration options. Any feedback would be appreciated.

@phairoh
Copy link

phairoh commented Oct 5, 2016

@borysn I'm sorry, but I've never used bootstrap-loader. Taking a quick look, though, it appears that there are 2 versions available on npm: v1 and v2 for webpack v1 and v2, respectively, and v2 is still in beta (as is webpack v2). Just doing npm install bootstrap-loader installs v2 by default so make sure that all your versions match up.

@dtothefp
Copy link

@borysn this took me a bit to figure out because I had sourcemaps enabled in a chain from

sass-loader => postcss-loader => css-loader => style-loader

some of these I use a mix between query params in the loader string, the query loader option and the config such as sassLoader or postcss on my webpack config. Checking out the changelog you can see the example PR for upgrading https://github.com/angular/angular-cli/pull/2237/files. One thing that isn't accounted for is that inside the SASS loader and CSS loader they use this.options to access not only options from the config such as config.postcss but also use it to access webpack config properties such as output.path and context. When I put these into my options with the LoaderOptionsPlugin all works. Seems scary because I'm unsure what other configs other loaders might use, if you want to be extra safe you could just merge your entire webpack config into your options. I made a little transform webpack1 to webpack2 script just in case the API changes further

import {LoaderOptionsPlugin} from 'webpack';

const webpackConfigWhitelist = [
  'amd',
  'bail',
  'cache',
  'context',
  'dependencies',
  'devServer',
  'devtool',
  'entry',
  'externals',
  'loader',
  'module',
  'name',
  'node',
  'output',
  'plugins',
  'profile',
  'recordsInputPath',
  'recordsOutputPath',
  'recordsPath',
  'resolve',
  'resolveLoader',
  'stats',
  'target',
  'watch',
  'watchOptions'
];
const skip = ['methods', 'debug'];

/**
 * Reduce over the loaders to transform `module.{preLoaders,loaders,postLoaders}` syntax
 * @param {Object} moduleConfig webpack config for `.module` property
 * @return {Array} match `module.rules` syntax https://github.com/TheLarkInn/angular-cli/blob/63801b48fa4ec0b48005ceed74bd0c03854b4c8e/packages/angular-cli/models/webpack-build-common.ts#L44
 */
function loaderReducer(moduleConfig) {
  return Object.keys(moduleConfig).reduce((list, name) => {
    const loaderList = moduleConfig[name];
    let enforce;

    switch (name) {
      case 'preLoaders':
        enforce = 'pre';
        break;
      case 'postLoaders':
        enforce = 'post';
        break;
    }

    const rules = enforce ?
      loaderList.map(loader => Object.assign(loader, {enforce})) :
      loaderList;

    list.push(...rules);

    return list;
  }, []);
}

/**
 * Utility to transform properties not accepted since `v2.1.0-beta.23`
 * @param {Object} webpackConfig config passed to the `webpack` compiler
 * @return {Object}
 */
export default function(webpackConfig) {
  const keys = Object.keys(webpackConfig);
  const options = {};

  const webpack2Config = keys.reduce((acc, key) => {
    if (skip.includes(key)) return acc;

    const val = webpackConfig[key];

    if (!webpackConfigWhitelist.includes(key)) {
      options[key] = val;
    } else if (key === 'module') {
      acc[key] = {};
    } else {
      acc[key] = val;
    }

    if (key === 'context' || key === 'output') {
      options[key] = val;
    }

    return acc;
  }, {});

  webpack2Config.module.rules = loaderReducer(webpackConfig.module);
  webpack2Config.plugins.push(
    new LoaderOptionsPlugin(
      Object.assign({}, {options})
    )
  );

  return webpack2Config;
}

@binarious
Copy link

I had to add this workaround bholloway/resolve-url-loader#33 (comment) to get rid of these errors:

ERROR in ./~/css-loader!./~/resolve-url-loader!./~/sass-loader?sourceMap!./~/bootstrap-loader/lib/bootstrap.styles.loader.js!./~/bootstrap-loader/no-op.js
Module build failed: TypeError: Cannot read property 'path' of undefined
    at Object.resolveUrlLoader (/Users/MYUSER/projects/MYAPP/node_modules/resolve-url-loader/index.js:38:55)
@ ./~/style-loader!./~/css-loader!./~/resolve-url-loader!./~/sass-loader?sourceMap!./~/bootstrap-loader/lib/bootstrap.styles.loader.js!./~/bootstrap-loader/no-op.js 4:14-164 13:2-17:4 14:20-170
@ ./~/bootstrap-loader/lib/bootstrap.loader.js!./~/bootstrap-loader/no-op.js
@ ./~/bootstrap-loader/loader.js
@ ./src/app/app.module.ts
@ ./src/app/index.ts
@ ./src/main.browser.ts
@ multi main

@luchillo17
Copy link

Hi, i'm using webpack 2.1.0-beta.25 and having this error still, what am i doing wrong?

loader:

      {
          test: /\.scss$/,
          loaders: [
            // ExtractTextPlugin.extract("style", "css?sourceMap"),
            'to-string-loader',
            'css-loader',
            'resolve-url-loader',
            'sass-loader' +
            '?sourceMap&' +
            'outputStyle=expanded&' +
            'root=' + helpers.root('src') + '&' +
            '&includePaths[]' + helpers.root('node_modules') + '&' +
            '&includePaths[]' + helpers.root('src')
          ]
        },

LoaderOptions plugin:

      new LoaderOptionsPlugin({
        options: {
          context: helpers.root('src'),
          outupt: {
            path: helpers.root('www')
          },
          sassLoader: {
            includePaths: [
              'node_modules', 'bower_components', 'app', '.'
            ]
          }
        }
      }),

@LiTiang
Copy link

LiTiang commented Oct 24, 2016

@phairoh,

i spend over 10 hr to fight the bugs,
but i still have no idea how to fix that, please help

My project is based on Angular2-webpack-starter

Almost all of my scss file located in src/app/public/scss/

except one of the file called app.style.scss located in app/

and the content of it(app.style.scss) is showing below

@import "~compass-mixins"; 
@import "~breakpoint-sass";
@import "~susy";
@import "~font-awesome/scss/font-awesome";
@import "~normalize-scss"; 
@import "public/scss/abstracts/index";
@import "public/scss/base/reset";
@import "public/scss/CSSObjects/index";
@import "public/scss/utilities/extend";
@import "public/scss/page/index";

The following is partial content of webpack.common.js

module: {
    rules: [
        {
              test: /\.scss$/,
              exclude: /node_modules/,
              use: [ 'raw-loader', 'css-loader', 'resolve-url-loader', 'sass-loader?sourceMap']
         }
    ]
}
  • If i change sass-loader?sourceMap to sass-loader

i get the ERROR : Cannot read property 'path' of undefined at Object.resolveUrlLoader

this is caused by resolve-url-loader


  • If i change sass-loader to sass-loader?sourceMap

i get the ERROR : Path must be a string. Received undefined

this is caused by sourceMap parameter

@imtiazwazir
Copy link

removing the ?sourceMap solved my problem

@dtothefp
Copy link

dtothefp commented Oct 24, 2016

@LiTiang as mentioned previously if you add context and output to your loader options this should fix your problem. If you look through source code for the sass loader it uses context if sourcemaps option is enabled, and I think the css loader uses something off of output.

plugins: [
    new LoaderOptionsPlugin({
       context: config.context,  // config is your webpack config object
       output: config.output,
       sassLoader: // your sass loader options
    })
]

@justin808
Copy link
Contributor

@dtothefp @LiTiang @imtiazwazir Is this doc issue? Or should we have a code PR?

@Andrey-Pavlov
Copy link

@dtothefp Can you show how to use it for https://github.com/AngularClass/angular2-webpack-starter ?

@Bariyard
Copy link

following the wiki How to use Bootstrap 3 and Sass and ng2 bootstrap

I modify config/webpack.common.js

        {
                test: /\.(sass|scss)$/,
                loaders: ['css-to-string-loader', 'css-loader?sourceMap', 'resolve-url', 'sass-loader?sourceMap']
        },
        { 
                test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, 
                loader: "url?limit=10000&minetype=application/font-woff" 
        },
        { 
                test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file" 
        },

to this

        {
                 test: /\.scss$/,
                 loaders: ['raw-loader', 'sass-loader']
        },
        { 
                  test: /\.(woff2?|ttf|eot|svg)$/, 
                  loader: 'url?limit=10000' 
        },

and it's work. Not sure what's going on though

@YamiOdymel
Copy link

Changed devtool: 'source-map' to devtool: 'eval' solved my problem temporary.

@borislemke
Copy link

@phairoh his answer has fixed my issue but I had to add it inside webpack.dev.js instead of webpack.common.js (if you are using Angular 2 Starter)

@luchillo17
Copy link

luchillo17 commented Dec 9, 2016

@LiTiang, @borislemke I have this issue as well, using Luchillo/angular2-webpack-starter, a fork of AngularClass/angular2-webpack-starter.

The only thing working for me is to either disable source maps, or set the options plugin in the webpack.dev.js as stated by @borislemke.

I suspect the one plugin from the webpack.common.js file is being overrided instead of merged, is there a way to set it in the common config so it works in prod without specifying it?

At the end i ended up putting the includePaths config in the query property of the loader in webpack.common.js and both context & output are duplicated in both webpack.dev.js & webpack.prod.js configs (should be in common to avoid duplication), for now at least.

@borislemke
Copy link

@Luchillo depending on how much you value your code, it is not recommended to have source maps in production. But glad that you found a fix for your case!

@luchillo17
Copy link

@borislemke I'm not using sourcemaps in production, i only duplicated the LoaderOptionsPlugin config with the small difference on the debug option in production.

@jhnns
Copy link
Member

jhnns commented Feb 7, 2017

The LoaderOptionsPlugin can be used to override the webpack options that can be accessed inside the loader via this.options. If you do that, you need to provide all the information the loader is reading from this object.

Usually, you don't need to do that. It is just for compatibility reasons to give you the full control. In all regular cases, you can just use loader options (they are also called loader queries) in your loader configuration. The loader will read these options from this.query (unfortunate naming).

@vteivans
Copy link

vteivans commented Feb 7, 2017

Having this same issue on webpack@2.2.1, when passing source map through query or options object, I get this error: TypeError: Path must be a string. Received undefined.

@jhnns
Copy link
Member

jhnns commented Feb 7, 2017

@vteivans as previously pointed out: If you're using the LoaderOptionsPlugin you also need to specify a context:

    new LoaderOptionsPlugin({
       context: config.context
    })

But you should not need the LoaderOptionsPlugin.

@alexander-akait
Copy link
Member

Please update to latest webpack version and sass-loader version 👍

Closing this out, please feel free to reopen if this doesn't resolve your issue. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests