FormidableLabs / inspectpack

An inspection tool for Webpack frontend JavaScript bundles.
MIT License
592 stars 20 forks source link

[BUG] Could not analyze bundle problems. Error: Unable to find project root package.json #45

Closed derkjn closed 7 years ago

derkjn commented 7 years ago

Whenever I try to start webpack-dashboard the following error occurs:

Could not analyze bundle problems.                                                                          ││                                   │
│ Error: Unable to find project root package.json                                                             ││                                   │
│     at Versions.getData (/Users/ignitestudio1/Sites/bluerock/web/app/themes/theme/node_modules/inspect   ││ Success                           │
│ pack/lib/actions/versions.js:308:14)                                                                        ││                                   │
│     at Bundle.create (/Users/ignitestudio1/Sites/bluerock/web/app/themes/theme/node_modules/inspectpac   ││                                   │
│ k/lib/actions/base.js:97:16)                                                                                │└───────────────────────────────────┘
│     at Immediate.setImmediate (/Users/ignitestudio1/Sites/bluerock/web/app/themes/theme/node_modules/i   │┌─Operation─────────────────────────┐
│ nspectpack/lib/models/bundle.js:278:7)                                                                      ││                                   │
│     at runCallback (timers.js:672:20)                                                                       ││                                   │
│     at tryOnImmediate (timers.js:645:5)                                                                     ││                                   │
│     at processImmediate [as _immediateCallback] (timers.js:617:5)                                           ││ idle (3s)                         │
│ Could not analyze bundle problems.                                                                          ││                                   │
│ Error: Unable to find project root package.json                                                             ││                                   │
│     at Versions.getData (/Users/ignitestudio1/Sites/bluerock/web/app/themes/theme/node_modules/inspect   │└───────────────────────────────────┘
│ pack/lib/actions/versions.js:308:14)                                                                        │┌─Progress──────────────────────────┐
│     at Bundle.create (/Users/ignitestudio1/Sites/bluerock/web/app/themes/theme/node_modules/inspectpac   ││                                   │
│ k/lib/actions/base.js:97:16)                                                                                ││                                   │
│     at Immediate.setImmediate (/Users/ignitestudio1/Sites/bluerock/web/app/themes/theme/node_modules/i   ││                                   │
│ nspectpack/lib/models/bundle.js:278:7)                                                                      ││ 0%                                │
│     at runCallback (timers.js:672:20)                                                                       ││                                   │
│     at tryOnImmediate (timers.js:645:5)                                                                     ││                                   │
│     at processImmediate [as _immediateCallback] (timers.js:617:5)  

The project I'm working on is a WordPress project. Webpack is started from the theme folder which lives in /web/app/themes/theme/package.json.

My webpack.config.js is as follows:

'use strict'; // eslint-disable-line

const webpack = require('webpack');
const path = require('path');
const merge = require('webpack-merge');
const CleanPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
var DashboardPlugin = require('webpack-dashboard/plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');

const CopyGlobsPlugin = require('copy-globs-webpack-plugin');
const config = require('./config');

const assetsFilenames = (config.enabled.cacheBusting) ? config.cacheBusting : '[name]';
const sourceMapQueryStr = (config.enabled.sourceMaps) ? '+sourceMap' : '-sourceMap';

let webpackConfig = {
  context: config.paths.assets,
  entry: config.entry,
  devtool: (config.enabled.sourceMaps ? '#source-map' : undefined),
  output: {
    path: config.paths.dist,
    publicPath: config.publicPath,
    filename: `scripts/${assetsFilenames}.js`,
  },
  stats: {
    hash: false,
    version: false,
    timings: false,
    children: false,
    errors: false,
    errorDetails: false,
    warnings: false,
    chunks: false,
    modules: false,
    reasons: false,
    source: false,
    publicPath: false,
  },
  module: {
    noParse: [
      /node_modules[\\/]video\.js/,
    ],
    rules: [
      {
        enforce: 'pre',
        test: /\.js?$/,
        include: config.paths.assets,
        use: 'eslint',
      },
      {
        enforce: 'pre',
        test: /\.vue$/,
        use: 'eslint',
        exclude: /node_modules/,
      },
      {
        test: /\.js$/,
        exclude: [/(node_modules|bower_components)(?![/|\\](bootstrap|foundation-sites))/],
        include: [config.paths.assets, path.join(process.cwd(), 'vendor/igniteonline')],
        use: [
          {loader: 'cache'},
          {
            loader: 'babel',
            query: {
              presets: [[path.resolve('./node_modules/babel-preset-es2015'), { modules: false }]],
              cacheDirectory: true,
            },
          }],
      },
      {
        test: /\.css$/,
        include: config.paths.assets,
        use: ExtractTextPlugin.extract({
          fallback: 'style',
          use: [
            {loader: 'cache'},
            `css?${sourceMapQueryStr}`,
            {
              loader: 'postcss',
              options: {
                sourceMap: true,
                config: {
                  path: path.join(process.cwd(), 'resources/assets/build'),
                },
              },
            },
          ],
        }),
      },
      {
        test: /\.scss$/,
        include: config.paths.assets,
        use: ExtractTextPlugin.extract({
          fallback: 'style',
          use: [
            {loader: 'cache'},
            `css?${sourceMapQueryStr}`,
            {
              loader: 'postcss',
              options: {
                sourceMap: true,
                config: {
                  path: path.join(process.cwd(), 'resources/assets/build'),
                },
              },
            },
            `resolve-url?${sourceMapQueryStr}`,
            `sass?${sourceMapQueryStr}`,
          ],
        }),
      },
      {
        test: /\.(png|jpe?g|gif|svg|ico)$/,
        include: config.paths.assets,
        exclude: path.join(config.paths.assets, 'images/admin'),
        loader: 'file',
        options: {
          name: `[path]${assetsFilenames}.[ext]`,
        },
      },
      {
        test: /\.(png|jpe?g|gif|svg|ico)$/,
        include: path.join(config.paths.assets, 'images/admin'),
        loader: 'file',
        options: {
          name: '[path][name].[ext]',
        },
      },
      {
        test: /\.(ttf|eot|otf)$/,
        include: config.paths.assets,
        loader: 'file',
        options: {
          name: `[path]${assetsFilenames}.[ext]`,
        },
      },
      {
        test: /\.woff2?$/,
        include: config.paths.assets,
        loader: 'url',
        options: {
          limit: 10000,
          mimetype: 'application/font-woff',
          name: `[path]${assetsFilenames}.[ext]`,
        },
      },
      {
        test: /\.(ttf|eot|otf|woff2?|png|jpe?g|gif|svg)$/,
        include: /node_modules|bower_components/,
        loader: 'file',
        options: {
          name: `vendor/${config.cacheBusting}.[ext]`,
        },
      },
      {
        test: /modernizr\.js$/,
        use: 'exports?window.Modernizr',
      },
      {
        test: /\.vue$/,
        use: 'vue',
      },
    ],
  },
  resolve: {
    modules: [
      config.paths.assets,
      'node_modules',
      'bower_components',
      'vendor/igniteonline',
    ],
    enforceExtension: false,
    alias: {
      vue: config.enabled.optimize ? 'vue/dist/vue.min.js' : 'vue/dist/vue.js',
      'video.js': 'video.js/dist/video.js',
      "TweenLite": path.resolve('node_modules', 'gsap/src/uncompressed/TweenLite.js'),
      "TweenMax": path.resolve('node_modules', 'gsap/src/uncompressed/TweenMax.js'),
      "TimelineLite": path.resolve('node_modules', 'gsap/src/uncompressed/TimelineLite.js'),
      "TimelineMax": path.resolve('node_modules', 'gsap/src/uncompressed/TimelineMax.js'),
      "ScrollMagic": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/ScrollMagic.js'),
      "animation.gsap": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap.js'),
      "debug.addIndicators": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators.js'),
    },
  },
  resolveLoader: {
    moduleExtensions: ['-loader'],
  },
  externals: {
    jquery: 'jQuery',
    'window.jsParams': 'jsParams',
    jsParams: 'jsParams',
    'window.google': 'google',
    google: 'google',
  },
  plugins: [
    new CleanPlugin([config.paths.dist], {
      root: config.paths.root,
      verbose: false,
    }),
    /**
     * It would be nice to switch to copy-webpack-plugin, but
     * unfortunately it doesn't provide a reliable way of
     * tracking the before/after file names
     */
    new CopyGlobsPlugin({
      pattern: config.copy,
      output: `[path]${assetsFilenames}.[ext]`,
      manifest: config.manifest,
    }),
    new ExtractTextPlugin({
      filename: `styles/${assetsFilenames}.css`,
      allChunks: false,
      disable: (config.enabled.watcher),
    }),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      'window.jQuery': 'jquery',
      Tether: 'tether',
      'window.Tether': 'tether',
      'window.jsParams': 'jsParams',
      jsParams: 'jsParams',
      'window.google': 'google',
      google: 'google',
      videojs: 'video.js',
      'window.videojs': 'video.js',
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: config.enabled.optimize,
      debug: config.enabled.watcher,
      stats: { colors: true },
    }),
    new webpack.LoaderOptionsPlugin({
      test: /\.js$/,
      options: {
        eslint: { failOnWarning: false, failOnError: true },
      },
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'node-static',
      filename: config.env.production ? `vendor/node-static-[hash:8].js` : `vendor/node-static.js`,
      minChunks(module) {
        const context = module.context;
        return context && context.indexOf('node_modules') >= 0;
      },
    }),
    new StyleLintPlugin({
      failOnError: ! config.enabled.watcher,
      syntax: 'scss',
    }),
  ],
};

/* eslint-disable global-require */ /** Let's only load dependencies as needed */

if (config.enabled.optimize) {
  webpackConfig = merge(webpackConfig, require('./webpack.config.optimize'));
}

if (!config.env.production && !config.enabled.watcher) {
  webpackConfig.plugins.push(new BundleAnalyzerPlugin({
    analyzerMode: 'static',
  }));
}
if (config.env.production) {
  webpackConfig.plugins.push(new webpack.NoEmitOnErrorsPlugin());
  webpackConfig.plugins.push(new webpack.optimize.ModuleConcatenationPlugin());
  // webpackConfig.plugins.push(new webpack.DefinePlugin({
  //   'process.env': {
  //     NODE_ENV: 'production',
  //   },
  // }));
}

if (config.enabled.cacheBusting) {
  const WebpackAssetsManifest = require('webpack-assets-manifest');

  webpackConfig.plugins.push(
    new WebpackAssetsManifest({
      output: 'assets.json',
      space: 2,
      writeToDisk: false,
      assets: config.manifest,
      replacer: require('./util/assetManifestsFormatter'),
    })
  );
}

if (config.enabled.watcher) {
  webpackConfig.entry = require('./util/addHotMiddleware')(webpackConfig.entry);
  webpackConfig = merge(webpackConfig, require('./webpack.config.watch'));
  webpackConfig.plugins.push(new DashboardPlugin());
}

module.exports = webpackConfig;

For your reference, the project is based on sage which reflects the structure of the theme folder in my project.

gartz commented 7 years ago

Same problem here.

ryan-roemer commented 7 years ago

@derkjn @gartz -- Can one of you give me a reproduction? If your projects aren't open source, then maybe a quick public repo with the minimum amount of code to cause the issue? I think it may be in the webpack aliases...

Also, as a totally unrelated side note, for code like:

"TweenLite": path.resolve('node_modules', 'gsap/src/uncompressed/TweenLite.js'),

I usually prefer the pattern of:

"TweenLite": require.resolve("gsap/src/uncompressed/TweenLite"),

In this way, you immediately get rid of any potential node_modules tree structure flattening issues (not a problem for top-level dependencies) and you're basically just letting Node do what it does with resolving (giving extensions searching and other things that path.resolve doesn't)

ryan-roemer commented 7 years ago

@tptee @kenwheeler -- What's the internal command that starts this part of webpack-dashboard or can you point me to the integrating code involved here?

It's a programming problem if Error: Unable to find project root package.json is happening because the option isn't passed within webpack-dashboard...

derkjn commented 7 years ago

@ryan-roemer Thank you for the quick response! I'll setup an example repo in the weekend and post the link to it here!

gartz commented 7 years ago

Well, I can't post my project here because it's a private one. But I don't have any kind of configuration like path.resolve or require.resolve.

To open webpack-dashboard, I'm not passing any params/args.

The difference is that I run it inside a docker container and I'm using webpack@3.5.5 with node@8.4.0.

I have patched webpack-dashboard to allow change the host so I can access the webpack-dashboard outside of the container. The PR is https://github.com/FormidableLabs/webpack-dashboard/pull/188 it's tested and working, however, I'm seeing that message about the package.json that I think it's unrelated to it.

In the weekend I can try to create another project open-source and reproduce the problem but I'm not sure if I will have the time because I'm traveling at the moment.

Hope this information help to find this bug (at least the webpack version and node version might be related to it, idk for sure).

Thanks for helping us.

tremby commented 7 years ago

I had this issue and got around it by unsetting context in my webpack configuration. That means the entry points etc need to be adjusted accordingly, of course.

derkjn commented 7 years ago

Hi @ryan-roemer , my apologies for the delay! I finally got some time to clone the repo where I'm getting the error. You can find it here: https://github.com/derkjn/webpack-dashboard-error I have to say that this morning the newest version of webpack-dashboard doesn't seem to be available via npm anymore, so I couldn't replicate the error anymore. Either way, once you clone the repo, navigate to the web/app/themes/ignitetheme and from there run npm i && npm run watch. That's what used to cause the error. You'll get php errors cause it a WP project but you can disregard those! Thank you! Edit: This is actually happening if you pull down webpack-dashboard@next

ugo-buonadonna commented 7 years ago

Seems like the problem is that, as pointed out by @tremby, package.json file is being resolved searching in the context folder specified in the webpack configuration.

gartz commented 7 years ago

@ugo-buonadonna that make sense to me because my context is a sub-folder. It should transverse up until finding the first package.json

ryan-roemer commented 7 years ago

@derkjn -- I've pulled down https://github.com/derkjn/webpack-dashboard-error and am trying to repro your issue with:

$ npm i
$ npm run watch

But the error I get is File to import not found or unreadable: ~bootstrap/scss/normalize.

Is there an additional install step I need to do?

derkjn commented 7 years ago

It's pulling down the wrong version of bootstrap. Can you use yarn? otherwise I'll change the package.json to a strict version of that package. Let me know! Thank you!

ryan-roemer commented 7 years ago

@derkjn -- Hmmm... running:

$ rm -rf node_modules
$ yarn install
$ yarn run watch

successfully compiles and I get no errors whatsoever.

Side note:

$ pwd
/PATH/TO/derkjn-webpack-dashboard-error/web/app/themes/ignitetheme

Are you running yarn from that directory? If so, do I need additional steps to see your error?

Here's what I see right now...

screen shot 2017-09-17 at 8 32 31 pm

derkjn commented 7 years ago

@ryan-roemer if you run yarn add -D webpack-dashboard@next and re-run yarn watch you'll get the error! thank you!

ryan-roemer commented 7 years ago

Repro'ed and confirmed it's a webpack-dashboard bug and not an inspectpack one. I'll keep this bug open and I'm working on a PR for webpack-dashboard. As suspected, problem is use of context outside of where the project root package.json and node_modules are.

ryan-roemer commented 7 years ago

Fix PR up at https://github.com/FormidableLabs/webpack-dashboard/pull/194