Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiple entry points to one bundle #15

Closed
jhnns opened this issue Aug 10, 2012 · 17 comments
Closed

Add multiple entry points to one bundle #15

jhnns opened this issue Aug 10, 2012 · 17 comments
Milestone

Comments

@jhnns
Copy link
Member

jhnns commented Aug 10, 2012

I want to use webpack to bundle unit tests in the test-folder. Therefore I want to search the test-folder for js-files and add these files to the bundle created by webpack. Is it possible to add multiple entry points like .addEntry() in browserify?

@sokra
Copy link
Member

sokra commented Aug 10, 2012

There is only one entry point in webpack. You need to require the "other" entry points in the single entry point.

// entry.js

require("./entryA");
require("./entryB");
require("./entryC");

Emulate multiple entry points

Make a text file with all your entry points:

entries.txt

./entryA
./entryB
./entryC

Make a loader which convert it to the real entry point:

entries.loader.js

module.exports = function(entries) {
  return entries
    .split(/\r\n?/g)
    .map(function(r) {
      return "require("+JSON.stringify(r)+")";
    })
    .join("\n");
}
webpack ./entries!./entries.txt assets/bundle.js

Should work, but not tested... If it doesn't work it's a bug... ;)

Require a whole directory

var directory = require.context("./tests");
directory.keys().forEach(directory);

See require.context example

@sokra
Copy link
Member

sokra commented Aug 10, 2012

If you don't want to modify your code, you can also do via a postLoader on the entry module, which adds some requires. You may load the additional modules from your config via this.options in loader context.

config = {
  postLoaders: [
    { test: /entry\.js$/, loader: path.join(__dirname, "additionalModules") }
  ],
  additionalModules: [
     "./entryA",
     "./entryB",
     "./entryC"
  ]
}
// additionalModules.loader.js
module.exports = function(source) {
  return source + "\n\n" + 
    this.options.additionalModules
      .map(function(r) {
        return "require("+JSON.stringify(r)+");";
      })
      .join("\n");
}

@jhnns
Copy link
Member Author

jhnns commented Aug 13, 2012

Yeah, I like the second solution better although it's still a bit cumbersome.

@sokra
Copy link
Member

sokra commented Aug 13, 2012

Maybe I add it as feature.

@jhnns
Copy link
Member Author

jhnns commented Aug 18, 2012

Would be cool!

@sokra
Copy link
Member

sokra commented Aug 25, 2012

Here is a good solution.

// testcases.js
var fs = require("fs");
var path = require("path");

var pathTests = path.join(__dirname, "test");

module.exports = fs.readdirSync(pathTests)
.map(function(test) {
  return path.join(pathTests, test);
}).filter(function(test) {
  return fs.statSync(test).isFile()
}).map(function(test) {
  return "require(" + JSON.stringify(test) + ");";
}).join("\n");

require("val!./testcases") or webpack val!testcases.js testBundle.js

@jhnns
Copy link
Member Author

jhnns commented Jan 14, 2013

👍 for webpack 0.9.x 😺

@sokra
Copy link
Member

sokra commented Jan 14, 2013

It's planned for 0.9, but I'm not sure about the API.

The default is:

new SingleEntryPlugin(context, entry)

MultiEntryPlugin may be something like this:

new MultiEntryPlugin(context, [entry1, entry2, ...])

@jhnns
Copy link
Member Author

jhnns commented Jan 14, 2013

Nice!

@sokra
Copy link
Member

sokra commented Jan 30, 2013

While webpack was used to be optimized for single page applications, you now are allowed to specify multiple entry points.

{
  output: {
    filename: "[name].bundle.js",
    chunkFilename: "[id].chunk.js"
  },
  plugins: [
    new SingleEntryPlugin(__dirname, "./page1", "page1"),
    new SingleEntryPlugin(__dirname, "./page2", "page2")
  ]
}

This creates multiple entry bundles, but they can share chunks.

page1.bundle.js - entry point 1
page2.bundle.js - entry point 2
1.chunk.js - chunk only used by entry point 1
2.chunk.js - chunk used by both entry points ;)

@sokra
Copy link
Member

sokra commented Jan 30, 2013

shortcut:

{
  output: {
    filename: "[name].bundle.js",
    chunkFilename: "[id].chunk.js"
  },
  entry: {
    page1: "./page1",
    page2: "./page2"
  }
}

@jhnns
Copy link
Member Author

jhnns commented Jan 30, 2013

Cool! 🍦

I'll test it. Our use-case was unit testing. In this case you usually don't have one single entry module, but a whole directory of tests. A test runner like mocha then just executes all modules within test.

@sokra sokra mentioned this issue Jan 30, 2013
6 tasks
@sokra
Copy link
Member

sokra commented Jan 31, 2013

The multi entry point:

{
  output: {
    filename: "[name].bundle.js",
    chunkFilename: "[id].chunk.js"
  },
  entry: ["./part1", "./part2"]
}

Or combine both:

{
  output: {
    filename: "[name].bundle.js",
    chunkFilename: "[id].chunk.js"
  },
  entry: {
    page1: ["./part1", "part2"],
    page2: "./page2"
  }
}

@sokra sokra closed this as completed Jan 31, 2013
@nick-thompson
Copy link

With this multiple entry points solution, is there a way to specify when the multiple entry points are invoked? It looks like webpack bundles each of the entry points into the main bundle and invokes each of them immediately. I'd like to tell webpack about my entry points so that it can analyze my dependency graph correctly, but I'd like to define when, for example, the second entry point is invoked. Is that possible?

@nick-thompson
Copy link

Sorry, I found an answer to my question reading the documentation more clearly. However, I noticed that when webpack builds out separate bundles for each entry point, it bundles critical dependencies into each of the bundles. My use case involves client-side routing and asynchronously invoking the second entry point. It seems simple enough to invoke the second entry point asynchronously, but it's clearly suboptimal to have an async require where shared dependencies are duplicated. Is there a way around this?

@sokra
Copy link
Member

sokra commented Nov 19, 2013

Maybe I misunderstood your question, but what you describe are not "multiple entry points". It's simply code splitting.

An entry point is the entry. You can compare it to a main function in a C programm. There should only be one per page. In a single page app you have only one entry point. In a multi page app you have one per page. The only difference from multi entry points to multiple bundles (calling webpack multiple times) is that multi entry points can share chunks.

I added an example to the webpack examples folder.

To continue the analogy to C programms: An entry point/chunk is similar to an executable. A chunk is similar to a SO/DLL. Only one executable can run at a time, it loads SOs/DLLs on demand. SOs/DLLs can be shared between executables.

If you want to load something on demand use code-splitting with require.ensure or AMD require.

// Client side routing
router.route("/pageA", function() {
  require(["pageA"], function(page) {
    page.show();
  });
});
router.route("/pageB/:arg", function(arg) {
  require(["pageB"], function(page) {
    page.show(arg);
  });
});

sokra added a commit that referenced this issue Nov 19, 2013
@puppybits
Copy link

Can you load an secondary entry with a different set of loaders?

For instance, I'm trying to create a service worker for offline caching. I've excluded the folder that contains the service worker and included it on the other. There are no calls to the service-worker.js (it's just manually loaded in the static index.html). The service-worker entry point is picking up React and hot loader instead of just going through Babel. Here's the salient parts of my config.

entry: {
     app: "app.js",
     'service-worker': 'persistence/service-worker.js'
},
module: {
    loaders:[{
        test: /\.js|\.jsx/,
        loaders: ["react-hot", "jsx?harmony", "babel"],
        exclude: /persistence/
    }, {
        test: /service\-worker\.js/,
        loaders: ["babel"],
        include: /persistence/
  }]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants