Pete
Pete

Reputation: 58462

webpack parse node_modules in same way as other js files

I have taken over a project that is using webpack and I am not too au fait with how it all hangs together yet but I am having issues when moving code out of the project into npm packages - we are trying to make some js npm packages so we can reuse them in several projects.

Here is an example - if I have the following code in the project:

const combinedFilters = {
  ...currentFilters,
  ...filters,
};

This will compile with no issues, yet if I move it into an npm package, I get the following error:

Module parse failed: C:\Code Team Services\Web\SiteFiles\src\node_modules\@private\search\filter\SearchBaseFilter.js Unexpected token(31: 6)
You may need an appropriate loader to handle this file type.
|     // Combine new filters with old filters.
|     const combinedFilters = {
|       ...currentFilters,
|       ...filters,
|     };

This is my webpack config - is there something I can add (or remove) in here to make the loader parse npm packges too?

/* eslint-disable func-names, no-useless-escape, object-shorthand */

// modules
const merge = require('webpack-merge');
const path = require('path');
const webpack = require('webpack');

// webpack plugins
const AssetsPlugin = require('assets-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin;

// load base configuration.
const baseConfig = require('./webpack.config');

// Get paths.
const paths = require('../core/paths');

module.exports = merge.smart(baseConfig, {
  cache: true,
    // Enable sourcemaps - see https://webpack.js.org/configuration/devtool/
    // Also see the point about using Uglify in combination with devtool and webpack
    // To disable sourcemaps comment out the line below
  devtool: 'source-map',

  // Define the entry points - each of these creates a new file.
  entry: {
    critical: ['sass/critical.scss'],
    styleguide: ['sass/styleguide.scss'],
    main: [
      'webpack/hot/dev-server',
      'webpack-hot-middleware/client?reload=true',
      'sass/main.scss',
      'js/main',
    ],
  },

  module: {
    rules: [
      {
        test: /\.(eot|ttf|woff|woff2)(\?.+)?$/,
        // Use the file-loader to include referenced fonts in dist folder.
        use: ['file-loader'],
      },
      {
          test: /\.(jpeg|jpg|gif|png|svg)(\?.+)?$/,
          use: [
            {
                // Use the url-loader to convert images to Data URIs.
                loader: 'url-loader',
                options: { limit: 10000 },
            },
            //{
            //    // Use the image-webpack-loader to optimize images and reduce overall file size.
            //    loader: 'image-webpack-loader',
            //},
          ],
      }
    ],
  },

  output: {
    // Define file naming convention - chunkhash is used to bypass the browser cache.
    chunkFilename: '[name].js',
    filename: '[name].js',

    // Define where generated assets will be located.
    path: paths.dist,

    // Define URL for output file path (as above).
    publicPath: paths.mvcAppPath + '/sitefiles/dist/',
  },

  plugins: [
    // Remove existing assets from dist folder.
    new CleanWebpackPlugin([paths.dist], {
      exclude: ['.gitignore', 'fallback'],
      root: paths.sitefiles,
    }),
    // Create JSON file containing the names of generated assets - used by styleguide and MVC site.
    new AssetsPlugin({
      filename: 'assets.json',
      path: paths.dist,
    }),
    // Reduce number of locales loaded by Moment JS.
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en-gb/),
    // Define constants to be accessed in source code.
    new webpack.DefinePlugin({
      // The Google Maps API key.
      GOOGLE_MAPS_API_KEY: JSON.stringify(''),
      // The URL prefix for local API calls.
      URL_VIRTUAL_PATH: JSON.stringify(paths.mvcAppPath),
      // This enables production mode on some modules.
      'process.env': {
        NODE_ENV: JSON.stringify('development'),
      },
    }),
    // Use the ExtractTextPlugin to move CSS to a separate file.
    new ExtractTextPlugin({
      allChunks: true,
      disable: false,
      filename: '[name].css',
    }),
    // Write bundle statistics to file for analysis and debugging tools.
    new StatsWriterPlugin({
      transform(data, opts) {
        const stats = opts.compiler.getStats().toJson({ chunkModules: true });
        return JSON.stringify(stats, null, 2);
      },
    }),
    // Enable HMR (https://webpack.js.org/guides/hot-module-replacement/).
    new webpack.HotModuleReplacementPlugin(),
    // Do not write files to disk when errors occur during bundling.
    new webpack.NoEmitOnErrorsPlugin(),
  ],
});

This is the base webpack config:

/* eslint-disable func-names, no-useless-escape, object-shorthand */

// webpack plugins
const ExtractTextPlugin = require('extract-text-webpack-plugin');

// Get paths.
const paths = require('../core/paths');

const baseConfig = {
  // These modules will be loaded outside of webpack e.g. via a CDN.
  externals: {
    jquery: 'jQuery',
  },

  // Define which loaders will be used for different file extensions.
  module: {
    rules: [{
        test: /\.html$/,
        use: [
          // Use the html-loader to parse and minify HTML imports.
          'html-loader',
        ],
      },
      {
        test: /\.js$/,
        use: [{
          // Use the eslint-loader to validate the JS files before bundling.
          loader: 'eslint-loader',
          options: {
            ignorePath: paths.eslintIgnore
          },
        }, ],
        enforce: 'pre',
        include: [paths.js],
        exclude: [paths.vendor],
      },
      {
        test: /\.js$/,
        use: [{
          // Use the babel-loader to transpile the JS to browser-compatible syntax.
          loader: 'babel-loader',
        }],
        include: [paths.js],
        exclude: [paths.vendor],
      },
      {
        test: /\.(css|scss)$/,
        // Use the ExtractTextPlugin to move CSS to a separate file.
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [{
              // Use the css-loader to parse and minify CSS imports.
              // N.B Sourcemaps enabled, but wont be output if devtool setting is commented out
              loader: 'css-loader',
              options: {
                autoprefixer: false,
                sourceMap: true
              },
            },
            {
              // Use the postcss-loader to add vendor prefixes via autoprefixer.
              // N.B Sourcemaps enabled, but wont be output if devtool setting is commented out
              loader: 'postcss-loader',
              options: {
                config: {
                  path: paths.postcssConfig
                },
                sourceMap: true
              },
            },
            {
              // Use the sass-loader to parse and minify CSS imports.
              // N.B Sourcemaps enabled, but wont be output if devtool setting is commented out
              loader: 'sass-loader?sourceMap',
              options: {
                sourceMap: true
              },
            },
          ],
          publicPath: paths.mvcAppPath + '/sitefiles/dist/',
        }),
      },
      {
        test: /loadcss\.js$/,
        use: [
          // Shim fg-loadcss to access the window object.
          'imports-loader?exports=>undefined',
          'exports-loader?window.loadCSS',
        ],
        exclude: [paths.js],
        include: /fg-loadcss/,
      },
      {
        test: /cssrelpreload\.js$/,
        use: [
          // Shim fg-loadcss to access the window object.
          'imports-loader?this=>window',
        ],
        exclude: [paths.js],
        include: /fg-loadcss/,
      },
      {
        test: /waypoints\.js$/,
        use: [
          // Shim waypoints to access the window object.
          'exports-loader?window.Waypoint',
        ],
        exclude: [paths.js],
        include: /waypoints/,
      },
      {
        test: /\.js$/,
        use: [
          // Shim videojs to force correct module syntax.
          'imports-loader?this=>window&exports=>false&define=>false',
        ],
        exclude: [paths.js],
        include: /video\.js/,
      },
      {
        test: /\.js$/,
        use: [
          // Shim videojs to force correct module syntax.
          'imports-loader?this=>window&exports=>false&define=>false',
        ],
        exclude: [paths.js],
        include: /videojs-youtube/,
      },
    ],

    noParse: [
      // Ignore prebuilt warning for videojs
      /[\/\\]video\.js$/,
      /[\/\\]video\.min\.js$/,
      /[\/\\]videojs-youtube/,
    ],
  },

  resolve: {
    alias: {
      // Add aliases for common source folders.
      fonts: paths.fonts,
      img: paths.img,
      js: paths.js,
      sass: paths.sass,
      vendor: paths.vendor,

      // Add aliases for vendor modules.
      'loadcss-core': 'fg-loadcss/src/loadcss',
      'loadcss-polyfill': 'fg-loadcss/src/cssrelpreload',
      'videojs-core': 'video.js/dist/video.js',
      'videojs-youtube': 'videojs-youtube/dist/Youtube',
      'waypoints-core': 'waypoints/lib/jquery.waypoints.js',
      'waypoints-infinite': 'waypoints/lib/shortcuts/infinite.js',
      'waypoints-inview': 'waypoints/lib/shortcuts/inview.js',
      'waypoints-sticky': 'waypoints/lib/shortcuts/sticky.js',
    },
  },
};

module.exports = baseConfig;

Upvotes: 2

Views: 1417

Answers (1)

Daniele Torino
Daniele Torino

Reputation: 1812

The problem is that node_modules is usually excluded in webpack configurations. In your case it is probably contained in the paths.vendor variable that is excluded. Path's that should still be included can be added to the include option (in your case it contains the value of paths.js).

See https://webpack.js.org/configuration/module/#rule-exclude and https://webpack.js.org/configuration/module/#rule-include.

Note that the value can also be an array, so you can leave your configuration as it is and just add additional include paths or conditions to the array.

Upvotes: 2

Related Questions