简体   繁体   中英

Independent chunk files with webpack

I am building a component library and I am using Webpack to bundle it. Some components only rely on html templates, css and JavaScript that I've written, but some components require external libraries.

What I'd like to achieve is a vendor.js that is optional to include if the component you want to use needs it.

For instance, If a user only needs a component without vendor dependencies, it would suffice that they use main.bundle.js which only contains my own code.

In my index.js , I have the following imports:

import { Header } from './components/header/header.component';
import { Logotype } from './components/logotype/logotype.component';
import { Card } from './components/card/card.component';
import { NavigationCard } from './components/navigation-card/navigation-card.component';
import { AbstractComponent } from './components/base/component.abstract';
import { Configuration } from './system.config';

import 'bootstrap-table';

import './scss/base.scss';

All of these imports are my own, expect for bootstrap-table .

I have configured Webpack like this:

const webpack = require('webpack');

const path = require('path');

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

const extractScss = new ExtractTextPlugin({
    filename: "[name].bundle.css"
});

module.exports = {
    entry:  {
        main: './src/index.ts'
    },
    output: {
        path: path.resolve(__dirname, 'dist/release'),
        filename: "[name].bundle.js",
        chunkFilename: "[name].bundle.js"
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor', // Specify the common bundle's name.
            minChunks: function (module) {
                // Here I would like to tell Webpack to give 
                // each bundle the ability to run independently
                return module.context && module.context.indexOf('node_modules') >= 0;
            }
        }),
        extractScss
    ],
    devtool: "source-map",
    resolve: {
        // Add `.ts` as a resolvable extension.
        extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
    },
    module: {
        rules: [
            // All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
            { test: /\.ts?$/, exclude: /node_modules/, loader: "awesome-typescript-loader" },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" },

            // Allows for templates in separate ejs files
            {test: /\.ejs$/, loader: 'ejs-compiled-loader'},

            {
                test: /\.scss$/,
                use: extractScss.extract({
                use: [{
                    loader: 'css-loader', options: {
                        sourceMap: true
                    }
                }, {
                    loader: 'sass-loader', options: {
                        soureMap: true
                    }
                }]
            })}
        ]
    }
}

This results in two .js files and one .css . However, webpacks common module loading functionality resides in vendor.js , and that renders my main unusable if I don't include vendor first, and it isn't always needed.

To sum it up, if a user only needs the footer (no external dependencies), this would suffice:
<script src="main.bundle.js"></script>

If the user wants to use the table, which has an external dependency, they would need to include both:
<script src="vendor.js"></script>
<script src="main.bundle.js"></script>

Right now, including only main.bundle.js gives me this error:
Uncaught ReferenceError: webpackJsonp is not defined .

I am aware that I can extract all common functionality by adding this after my vendor chunk is created in the Webpack config:

new webpack.optimize.CommonsChunkPlugin({
    name: 'common'
})

But this approach still requires the user to include two .js files.

How can I go about achieving this? It seems that it only differs 2 kb when I don't extract the common modules like I do above, and that is fine with me.

Turns out this is very easy to do if you can stand some manual work and actually understand what Webpack does (which I didn't). I solved it like this:

const webpack = require('webpack');

const path = require('path');

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

const extractScss = new ExtractTextPlugin({
    filename: "[name].bundle.css"
});

module.exports = {
    entry:  {
        main: './src/index.ts',
        vendor: './src/vendor/vendor.ts'
    },
    output: {
        path: path.resolve(__dirname, 'dist/release'),
        filename: "[name].bundle.js",
        chunkFilename: "[name].bundle.js"
    },
    plugins: [
        extractScss
    ],
    devtool: "source-map",
    resolve: {
        // Add `.ts` as a resolvable extension.
        extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
    },
    module: {
        rules: [
            // All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
            { test: /\.ts?$/, exclude: /node_modules/, loader: "awesome-typescript-loader" },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" },

            // Allows for templates in separate ejs files
            {test: /\.ejs$/, loader: 'ejs-compiled-loader'},

            {
                test: /\.scss$/,
                use: extractScss.extract({
                use: [{
                    loader: 'css-loader', options: {
                        sourceMap: true
                    }
                }, {
                    loader: 'sass-loader', options: {
                        soureMap: true
                    }
                }]
            })}
        ]
    }
}

In vendor.ts , I then simply import any vendor dependencies I have:

import 'jquery';
import 'bootstrap-table';

This results in two different files, both have Webpacks bootstrapping logic.

Hope this helps someone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM