Webpack: Error: configuration.module has an unknown property ‘preloaders’

I have a lot of entries now in my debug log, from all the random errors and bugs that I encounter during my regular work. I figure I might as well start sharing some of it on here as well. Who knows it might just save some poor soul out there a few hours of tearing their hair out! 😉

The problem

You just started a new webpack project and happily copied over an old webpack configuration to make a few tweaks to get the project set up. Or, maybe you decided suddenly to upgrade our webpack package. Suddenly, when you run webpack, you see the following error:

configuration.module has an unknown property ‘preloaders'

The solution

If you encounter this error, then it is more than likely you are using webpack version 2 and haven’t migrated your webpack version 1 configuration over yet.

In webpack version 2, there’s two gotchas related to this problem:

  1. The “loaders” section is now renamed to “rules”.
  2. The “preloaders” section is no more. Instead of a separate preloaders section, we need to move the preloading rules into the “rules” section with an enforce property set to “pre”.

Here’s an example of what the module section of the webpack configuration should like to fix this error message:

module: {
	rules: [
		{
			enforce: 'pre',
			test: /\.js$/,
			exclude: 'node_modules',
			loader: 'jshint-loader'
		},
		{
			test: /\.css$/,
			loader: "style!css!postcss",
		},
		// other loaders
	]
}

Background

I encountered this error last month, when I was trying to set up webpack in a new project. I innocently ran npm install webpack…but alas, inadvertently installed webpack version 2, which meant that lots of things were breaking with my old webpack v1 configuration file.  Lots of things changed with webpack version 2, which means that we need to make some updates to get up to speed with the new version.

For a more detailed migration guide for webpack version 1 to webpack version 2, check here: https://webpack.js.org/guides/migrating/.

Additional Resources

 

Algorithms: Javascript Array indexOf vs Binary Search vs Hash Access

I’ve been getting into algorithms lately, and I wanted to try out adding binary search to Simply Is, a simple type testing javascript utility I wrote a while back. But, surprisingly, it ended up being slower than the native Javascript array indexOf. Less surprisingly though, hash access was the fastest. Actually, creating a hash from the array then accessing it was actually still faster than the binary search (though slower than the native array indexOf).

My theory is that this result probably has to do with how Javascript works under the hood. Something worth looking into would be how Array indexOf is implemented in the Javascript source. It might be possible that since it’s built-in/operating at a lower level, there’s less overhead and thus performs better.


Binary search – 216,774 ops/sec

function binary_search(x,arr){
    if( typeof arr[0] === 'number' ){
        arr = arr.sort(function(x,y){ return Number(x) - Number(y) })
    }else{
        arr = arr.sort()
    }

    var min = 0,
        max = arr.length - 1,
        current_guess = Math.floor( (min + max)/2 )
        
    var found = false

    if( x === arr[current_guess] ){
        found = true
    }else if( x < arr[current_guess] ){ found = binary_search(x, arr.slice(min, current_guess) ) }else if( x > arr[current_guess] ){
        found = binary_search(x, arr.slice(current_guess + 1, max + 1))
    }

    return found
}

Array indexOf = 43,314,557 ops/second

var TEST_ARRAY = [2, 3, 17, 18, 22, 74, 25, 93, 43, 47, 48, 56, 59, 61, 64, 52, 71, 73, 75,37, 76, 77, 88, 21]
TEST_ARRAY.indexOf(73) > 0

Creating a hash from the array then accessing it = 809,269 ops/sec

   var TEST_HASH = {}
    TEST_ARRAY.forEach(function(value){
        TEST_HASH[value] = true
    })
    TEST_HASH[73]

(Existing) hash access = 90,671,807 ops/sec

TEST_HASH[73]

Either way, this result was somewhat surprising to me, since in terms of algorithms, binary search is supposed to be very fast. Then again, the comparison might not be completely fair, since the binary search is implemented at a higher level while the Array indexOf method is built-in. I wonder, though, how will it hold up if the array is very,very large? It’s possible that this result is only the case because the array that’s being searched is pretty small? Or, perhaps it has to do with the way I did the binary search (recursive calls on smaller array slices)? Maybe having to slice/create a new array is slowing it down?

Lots of possibilities for what may have led to this result. I’ll have to look into this a bit more one of these days.

Using Isotope with ReactJS

Isotope is a great layout alternative to Masonry, and recently it has been my preferred choice when going for a Masonry-like grid layout. But when I tried to add it in to a React application I’ve been working on, I encountered some issues with initialization. And things got reaaaally wonky when the grid items were dynamic and changed too. So here’s how I solved it.

I had a component for my product search results that rendered the product results that matched a user query then allowed users to filter them via a search box…as well as re-run the search again with different parameters. Each product result was displayed via the Product component, which essentially renders the product image, detailed specs, and then allows for selection/ordering.

The product data is retrieved from the ProductStore, which has data stored from a previous ajax request to an API server, which returns a JSON response with all the matching products. The product data retrieved is in something like the following format:

[
	{
		item_num: 0,
		name: "Awesome product",
		specs: [...] // an array of specifications
	},
	{
		item_num: 1,
		name: "Another product",
		specs: [...] // an array of specifications
	}
]

However, since we’re filtering the product data and also re-running the search with different search queries, the product data that needs to be displayed is dynamic. So, what we need is for the Isotope grid to adjust its layout accordingly every time the list of visible products changes due to user interaction.

The obvious solution would be to initialize Isotope in componentDidMount, then destroy it in componentWillUnmount. But when the product data changes….everything breaks. So how can we fix this so that even newly updated product results will be in an Isotope grid?

The solution is to remove the existing Isotope instance in componentWillUpdate, then reinitialize it in componentDidUpdate once the component has the new data. This is, of course, in addition to initializing Isotope during componentDidMount and destroying it in componentWillUnmount.

To initialize Isotope on a container element (in my case, .products):

$('.products').isotope({
	itemSelector: '.product',
    	layoutMode: 'masonry'
});

And to destroy/tear it back down:

$('.products').isotope('destroy');

Here’s a simplified version of what the final ProductSearch component looked like (note, JSX is commented out due to limitations of the Syntax highlighter):

var React = require('react');
var _ = require('lodash');
var Product = require('./Product');
var ProductFilters = require('./ProductFilters');
var ProductStore = require('./ProductStore');

var ProductSearch = React.createClass({
	getInitialState: function(){
		return {
			products: [],
			searchString: ""
		}
	},
	componentWillMount: function(){
		ProductStore.addChangeListener(this.handleReceiveData);
		this.setState({
			products: ProductStore.getProducts()
		})
	},
	handleReceiveData: function(){
		this.setState({
			products: ProductStore.getProducts()
		})
		console.log('data received from product store');
	},
	filterItems: function(event){
		this.setState({
			searchString: event.target.value
		});

	},
	render: function(){

		var vehicle = this.state.vehicle;

		// hey, if we have products stored in the state, display them
		if(this.state.products && this.state.products.length){
			var searchString = this.state.searchString.toLowerCase();
			var products = this.state.products.map(function(product){

				// combining the values of each product (e.g. item number, product description, technical details, color, etc into one string for search
				var productString = _.values(product).join("|").toLowerCase();

				// if there is no search string or if the search matches, then show the product
				if( !searchString || productString.match(searchString) ){
					// unfortunately, JSX doesn't play so well with the syntax highlighter. But this is JSX here
					return (
						//<Product product={product} key={product.model.toLowerCase() + product.finish}></Product>
					)
				}else{
					// otherwise, don't show the product in the results
					return "";
				}
			});
	
		}else{
			// no products were found
			var products = (
				//JSX <div>Sorry, nothing here.</div>
			);
		}

		return (
			/* JSX
			<div>
				<section id="products">
					<div>{products}</div>
				</section>
			</div>
			*/
		)
	},
	isDeviceMobile: function(){
		if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
		 return true;
		}
	},
	initIsotope: function(){
		$('.products').isotope({
	        	itemSelector: '.product',
	        	layoutMode: 'masonry'
	    	});
	},
	removeIsotope: function(){
		$('.products').isotope('destroy');
	},
	componentDidMount: function(){
		// initialize isotope only if there are products, and if the device isn't Mobile
		if(this.state.products && this.state.products.length > 0 && !this.isDeviceMobile()){
			this.initIsotope();
		}
	},
	componentWillUpdate: function(){
		this.removeIsotope();
	},
	componentDidUpdate: function(){
		if(this.state.products && this.state.products.length > 0 && !this.isDeviceMobile()){
	   		this.initIsotope();
	    }
	},
	componentWillUnmount: function(){
		this.removeIsotope();
		ProductStore.removeChangeListener(this.handleReceiveData);
	}
});

module.exports = ProductSearch;

Enjoy, and happy coding! 🙂