reactjswebpackwebpack-style-loaderhtml-webpack-plugin

import CSS and JS files using Webpack


I have a directory structure like this:

enter image description here

and inside node_modules:

 >node_modules
  >./bin
   >webpack.config.js
  >bootstrap
   >bootstrap.css
   >bootstrap.js

I need to generate separate CSS and JS bundles like this:

custom-styles.css, custom-js.js, style-libs.css, js-libs.js

where style-libs and js-libs should contain syles and js files of all libraries like bootstrap and jQuery. Here's what I have done so far:

webpack.config.js:

const path = require('path');
const basedir = path.join(__dirname, '../../client');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const stylesPath = path.join(__dirname, '../bootstrap/dist/css');

var ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
  watch: true,

  // Script to bundle using webpack
  entry: path.join(basedir, 'src', 'Client.js'),
  // Output directory and bundled file
  output: {
    path: path.join(basedir, 'dist'),
    filename: 'app.js'
  },
  // Configure module loaders (for JS ES6, JSX, etc.)
  module: {
    // Babel loader for JS(X) files, presets configured in .babelrc
    loaders: [
        {
            test: /\.jsx?$/,
            loader: 'babel',
            babelrc: false,
            query: {
                presets: ["es2015", "stage-0", "react"],
                cacheDirectory: true // TODO: only on development
            }
        },
        {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract("style-loader", "css-loader")
        },
    ]
  },
  // Set plugins (for index.html, optimizations, etc.)
  plugins: [
     // Generate index.html
     new HtmlWebpackPlugin({
        template: path.join(basedir, 'src', 'index.html'),
        filename: 'index.html'
     }),
     new ExtractTextPlugin(stylesPath + "/bootstrap.css", {
        allChunks: true,
     })
  ]
};

Client.js

import * as p from 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.jsx';

ReactDOM.render(<App />, document.getElementById('app'));

I am able to run the app and render all of the components correctly except loading the external JS and CSS file using webpack.

I'm not much experienced with webpack and found it really difficult to wrap my head around. Following are few simple questions:

1- Is this configuration correct? If yes, then how can I include my CSS and JS files in components using ES6. Something like import keyword.

2- Should I even be using webpack for CSS files?

3- How to specify individual directories for input and their respective output files in webpack? Something like all-custom.js should be output for custom1.js and custom2.js?

I know these are some very basic question and I tried Google but didn't find a single tutorial for Webpack that is simple and targets beginners.


Solution

  • After playing out with Webpack in multiple projects, I figured out how Webpack loads stuff. Since the question is still unanswered, I decided to do it myself for anybody with same need.

    Directory structure

    ->assets
      ->css
        ->my-style-1.css //custom styling file 1
        ->my-style-2.css //custom styling file 2
    
    ->src
      ->app
        ->app.js
        ->variables.js
    
      ->libs.js //require all js libraries here
      ->styles-custom.js //require all custom css files here
      ->styles-libs.js //require all style libraries here
    
    ->node_modules
    ->index.html
    ->package.json
    ->webpack.config.js
    

    Bundle 1 (main code of app)

    app.js: assuming this is main file and app starts from here

    var msgs = require('./variables');
    //similarly import other js files you need in this bundle
    
    //your application code here...
    document.getElementById('heading').innerText = msgs.foo;
    document.getElementById('sub-heading').innerText = msgs.bar;
    

    Bundle 2 (js modules)

    libs.js: this file will require all modules needed

    require('bootstrap');
    //similarly import other js libraries you need in this bundle
    

    Bundle 3 (external css files)

    styles-libs.js: this file will require all external css files

    require('bootstrap/dist/css/bootstrap.css');
    //similarly import other css libraries you need in this bundle
    

    Bundle 4 (custom css files)

    styles-custom.js: this file will require all custom css files

    require('../assets/css/my-style-1.css');
    require('../assets/css/my-style-2.css');
    //similarly import other css files you need in this bundle
    

    webpack.config.js

    const path = require('path');
    const webpack = require('webpack');
    const extractTextPlugin = require('extract-text-webpack-plugin');
    
    module.exports = {
        entry: {
            'app': './src/app/app.js', //specifying bundle with custom js files
            'libs': './src/libs.js', //specifying bundle with js libraries
            'styles-custom': './src/styles-custom.js', //specifying bundle with custom css files
            'styles-libs': './src/styles-libs.js', //specifying bundle with css libraries
        },
        module: {
            loaders: [
                //used for loading css files
                {
                    test: /\.css$/,
                    loader: extractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
                },
                //used for loading fonts and images
                {
                    test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
                    loader: 'file-loader?name=assets/[name].[hash].[ext]'
                }
            ]
        },
        output: {
            path: path.resolve(__dirname, 'dist'), //directory for output files
            filename: '[name].js' //using [name] will create a bundle with same file name as source
        },
        plugins: [
            new extractTextPlugin('[name].css'), //is used for generating css file bundles
    
            //use this for adding jquery
            new webpack.ProvidePlugin({
                $: 'jquery',
                jQuery: 'jQuery'
            })
        ]
    }
    

    index.html

    <head>
      <link rel="stylesheet" href="dist/styles-libs.css" />
      <link rel="stylesheet" href="dist/styles-custom.css" />
    </head>
    <body>
      <h2 id="heading"></h2>
      <h3>
        <label id="sub-heading" class="label label-info"></label>
      </h3>
      <script src="dist/libs.js"></script>
      <script src="dist/app.js"></script>
    </body>