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

Wrong chunks order also with chunksSortMode: 'none' #481

Closed
Ks89 opened this issue Nov 2, 2016 · 40 comments
Closed

Wrong chunks order also with chunksSortMode: 'none' #481

Ks89 opened this issue Nov 2, 2016 · 40 comments

Comments

@Ks89
Copy link

Ks89 commented Nov 2, 2016

I want to create two html pages based on ejs templates, injecting chunks into the body tag.

Pages are created and everything seems to be ok, but the order of chunks is wrong.

If I use chunksSortMode:'auto' for both files -> the first is ok (polyfills->vendor->app), but the second one no (admin->polyfills->vendor)

If I use chunksSortMode:'none' for both files -> both of them are wrong. The first one is (vendor->app->polyfills), the second one (vendor->admin->polyfills)

For the first file (with app) I can use 'auto', but for the second one, I'm obliged to create a crazy-custom-order function [p..-v...-a... (not alphabetical order)] (that i don't want to post here, because it's something the no one should see :( ).

new HtmlWebpackPlugin({
      title: TITLE,
      inject: true,
      chunksSortMode: 'auto', //ok only with auto
      chunks: ['polyfills', 'vendor', 'app'],
      template: TEMPLATE_PATH,
      filename: TEMPLATE_HTML
    }),
    new HtmlWebpackPlugin({
      title: TITLE_ADMIN,
      inject: true,
      chunksSortMode: 'none' //wrong with every value -> I'm using a crazy order function (very bad)
      chunks: ['polyfills', 'vendor', 'admin'],
      template: TEMPLATE_ADMIN_PATH,
      filename: TEMPLATE_ADMIN_HTML
    }),

The expected behaviour should be this:

  • chunksSortMode: 'none', chunks: ['polyfills', 'vendor', 'admin']
....polyfills... ....vendor... ....admin... - chunksSortMode: 'none', chunks: ['polyfills', 'vendor', 'app'] ....polyfills... ....vendor... ....app...

Every other behaviour with chunksSortMode: 'none' it is weird.

PS: I created my chunks in this way (probably, the cause of this issue is here...I really don't know):

entry: {
    polyfills: './src/polyfills.ts',
    vendor: './src/vendor.ts',
    app: './src/main.ts',
    admin: './src/admin.ts'
  },
........
new CommonsChunkPlugin({
      name: ['admin', 'app', 'vendor', 'polyfills'],
      minChunks: Infinity
    }),

I used: Nodejs 7.0.0, macOS Sierra, Webpack 2.1.0 beta 25, HtmlWebpackPlugin: 2.24.1

Thank u,
Ks89

@Sayan751
Copy link

Sayan751 commented Nov 4, 2016

I am also facing the same issue, and described the problem in details here.

@trungnguyenn
Copy link

I used chunksSortMode with custom function and it worked for me as a trick (alphabetical order)

chunks: ['vendor', 'polyfills', 'admin'],
chunksSortMode: function(a, b) {
   return (a.names[0] < b.names[0])? 1 : -1;
}

@Ks89
Copy link
Author

Ks89 commented Nov 6, 2016

Yes. Custom functions are working, but not the other values.

@humorHan
Copy link

humorHan commented Nov 7, 2016

This can only be a simple choice if it is positive or reverse.
Read the source to find in the function and then called the sort function, not too friendly, has been feedback

@jantimon
Copy link
Owner

jantimon commented Nov 7, 2016

none means that it takes the sort order from the webpack compiler.

@Ks89
Copy link
Author

Ks89 commented Nov 7, 2016

The problem is not that these functions aren't intuitive.
The problem is that they are broken, as explained in my post. It's also possible that this is a webpack issue. If 'none' means 'the same order of webpack' , this means that webpack has a bug.
I don't know.
But how can we check where is the problem?
Do you want a skeleton project to see this problem?

@jantimon
Copy link
Owner

jantimon commented Nov 7, 2016

Feel free to contribute :)
Add some tests install iron-node or setup the node inspector and open a pull request.
Please make sure that you support webpack1, webpack2 and don't break backwards compatibility

@humorHan
Copy link

humorHan commented Nov 8, 2016

'function', in alphabetical order, because the sort method is called internally.

@Ks89
Copy link
Author

Ks89 commented Nov 8, 2016

Yes, sorry.
Wrong word. I called functions the strings none and so on.

@humorHan
Copy link

humorHan commented Nov 8, 2016

@Ks89 'function', in alphabetical order, because the sort method is called internally.
Will the next version of the problem be solved

@jantimon
Copy link
Owner

Sorry @humorHan I really don't understand what you are trying to say

@humorHan
Copy link

@jantimon
Well, maybe I'll describe some of the problems, um... I'll describe it again.
For example, I have three JS files, I want to insert in a specific order to the HTML, but by setting a variety of chunksSortMode and can not be achieved. for example: a.js b.js c.js, I want to insert the HTML to achieve the following results :

<script src="./b.js"></script>
<script src="./a.js"></script>
<script src="./c.js"></script></body>
but,failed.

By looking at the source code to understand, it is possible because the source code inside the sort function, the loss of the flexibility of the parameters.
If you really can not understand it does not matter, I temporarily change the plugin source code to achieve the effect I want.
Thank you very much to answer questions!

@jantimon
Copy link
Owner

You can pass a function which is in full control of sorting your assets. Didn't that work for you?

@humorHan
Copy link

humorHan commented Nov 11, 2016

@jantimon
I tried to write a few function, but did not achieve the effect, whether it is because of the inside of the plug-in called the sort method?
I think, should remove the internal call ‘sort’ function to increase the flexibility.
that is, to remove the index.js source sort method, as follows:

index.js : about 335 line

if (typeof sortMode === 'undefined') {
sortMode = 'auto';
}
// Custom function
if (typeof sortMode === 'function') {
return chunks.sort(sortMode); // TODO Modify as: return sortMode(chunks);
}
// Disabled sorting:
if (sortMode === 'none') {
return chunkSorter.none(chunks);

}

@jantimon
Copy link
Owner

Haha no no that's fine.

Please read here how to write a comparison method:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

@jamesjieye
Copy link
Contributor

jamesjieye commented Nov 23, 2016

I did something like this to customize my chunk ordering. Basically, it will order the chunk the way you put the chunks in the array.

chunksSortMode: function (chunk1, chunk2) {
  var orders = ['manifest', 'style', 'vendor', 'app'];
  var order1 = orders.indexOf(chunk1.names[0]);
  var order2 = orders.indexOf(chunk2.names[0]);
  if (order1 > order2) {
    return 1;
  } else if (order1 < order2) {
    return -1;
  } else {
    return 0;
  }
}

@Ks89
Copy link
Author

Ks89 commented Dec 4, 2016

Finally, I created a skeleton project, as promised: https://github.com/Ks89/Angular2-webpack2-skeleton

Branches:

  • master (custom function based on @jamesjieye solution) -> working
  • chunckSortMode-auto -> broken (I'm sorry for the typo in the branch name :) )
  • chunksSortMode-dependency -> broken
  • chunksSortMode-none -> broken

run npm run buildDev and check ./dist/admin.html to see if the order is ok or not.

@humorHan
Copy link

humorHan commented Dec 5, 2016

@jamesjieye
If I want to achieve the following order, does your ordering function work?
//some codes

<script src="./manifest.js"></script> 
<script src="./styl. js"></script>
 <script src="./vendor.js"></script> 
<script src="./app.js"></script>

@jamesjieye
Copy link
Contributor

jamesjieye commented Dec 5, 2016

@humorHan

Yes, by specifying the order like this: var orders = ['manifest', 'style', 'vendor', 'app'];, the scripts will be like this.

<script src="./manifest.js"></script> 
<script src="./style. js"></script>
<script src="./vendor.js"></script> 
<script src="./app.js"></script>

BTW, if you want to exlcude style.js in the output, you can use this plugin https://github.com/jamesjieye/html-webpack-exclude-assets-plugin.

@humorHan
Copy link

humorHan commented Dec 5, 2016

@jamesjieye ok! thank you~

@bholben
Copy link

bholben commented Jan 21, 2017

@jamesjieye's custom function above works very nicely. If we step back and look at the root issue, I'm thinking the better solution is to design webpack such that the entry property can accept either an object or an array. The fact that we have to cobble together something to control order seems kind of silly to me.

@timc13
Copy link

timc13 commented Feb 1, 2017

yes! a sensible default ordering should be the array order.

@jamesjieye
Copy link
Contributor

@bholben totally agree! When I wanted to order the chunks, I was thinking passing an array to define the order. It would be much easier to use if the custom order function was built into the plugin itself.

@humorHan
Copy link

humorHan commented Feb 3, 2017

@jamesjieye yes,I also agree that once I tried to change the plug-in source code, can be sorted in accordance with the order of the incoming array, I feel more convenient

@anthonyettinger
Copy link

anthonyettinger commented Feb 10, 2017

Thanks to @jamesjieye

      chunksSortMode: function (chunk1, chunk2) {
        var orders = ['vendor', 'app'];
        var order1 = orders.indexOf(chunk1.names[0]);
        var order2 = orders.indexOf(chunk2.names[0]);

        return order1 - order2;
      }

ugly but works. i spent awhile trying to figure out raw-loader only worked once in awhile.

@kamihouse
Copy link

Tks @jamesjieye && @anthonyettinger, these are my settings for define resource sorting:

new HtmlWebpackPlugin({
    title: 'App Name',
    minify: {
        collapseWhitespace: true,
        keepClosingSlash: true,
        removeComments: true
    },
    chunksSortMode: (c1, c2) => {
        // Corrige bug da ordenação de assets.
        let orders = ['common', 'vendor', 'app'];
        let o1 = orders.indexOf(c1.names[0]);
        let o2 = orders.indexOf(c2.names[0]);
        return o1 - o2;
    },
    filename: '../index.html',
    favicon: './src/assets/images/favicon.ico',
    template: './src/assets/index.ejs'
})

@zhe-he
Copy link

zhe-he commented Mar 23, 2017

@kamihouse Can you show me your configuration information? thanks!

@lucastheisen
Copy link

One more way to do this:

const entryMap = [
    ["polyfills", path.join(root, "src", "polyfills.ts")],
    ["vendor", path.join(root, "src", "vendor.ts")],
    ["app", path.join(root, "src", "index.ts")],
];
const entry = Object.assign({}, 
    ...entryMap.map(([key, value]) => ({[key]: value})));
const chunkSorter = (a, b) => {
    const order = Object.assign({}, 
        ...entryMap.map(([key, value], index) => ({[key]: index})));
    return order[a.names[0]] - order[b.names[0]];
}

module.exports = {
    entry,
    ...
    plugins: [
        new HtmlWebpackPlugin({
            filename: "index.html",
            template: path.join(root, "src", "index.ejs"),
            chunksSortMode: chunkSorter,
        }),
    ]
    ...
}

Only real difference here is that the order is defined in the same place as the sorter, so you can't forget to update both locations when you add a new chunk...

@szimek
Copy link

szimek commented May 9, 2017

Would it make sense to add a new options (e.g. called manual) that would keep the order exactly as defined in chunks array?

@gregjacobs
Copy link

Just ran into this issue myself. Would be nice to have the order of the chunks array be the order of the files in the html.

@antony-oktana
Copy link

Same issue over here. Would be nice a manual option that just adds them as the names are added in the array.

@mb8z
Copy link

mb8z commented Jun 19, 2017

Well, I am new to the opensource community, not really know how to add something from myself, but

  1. Edit the lib/chunksorter.js and replacing the module.exports.none so the none function looks like this:
module.exports.none = function (chunks, originalChunksInput) {
  return chunks.sort((a, b) => originalChunksInput.indexOf(a.names[0]) - originalChunksInput.indexOf(b.names[0]));
};
  1. Edit the lib/index.js file and update the HtmlWebpackPlugin.prototype.sortChunks function, so it accepts one more argument (originalChunksInput) and edit it so:
// Sort mode auto by default:
  if (typeof sortMode === 'undefined') {
    sortMode = 'none';  // Change the default sortMode to none (if desired)
  }
...
// Disabled sorting:
  if (sortMode === 'none') {
    return chunkSorter.none(chunks, originalChunksInput); // Pass the additional argument to the function
  }
  1. Look for the compiler.plugin('emit',... and update the code below // Sort chunks comment, so it passes the previously mentioned argument of originalChunksInput:
// Sort chunks
    chunks = self.sortChunks(chunks, self.options.chunksSortMode, self.options.chunks);

Voila! This way you switched to the none as the default chunksSortMode option, and you provided a small change so the chunks are loaded in the way you put them into the chunks option.

Hope this helps somebody!

@mrukas
Copy link

mrukas commented Jul 2, 2017

An option to define the chunk order manually would be really great!
+1

@jantimon
Copy link
Owner

jantimon commented Jul 3, 2017

Merged in #684

@jantimon
Copy link
Owner

Released 2.30.0

@cleverboy32
Copy link

why i use chunksSortMode: manual or i write a function, all two no worker. and my version is the lastest. help ???

@Javierb
Copy link

Javierb commented Nov 2, 2017

In case you rather to set the order manually instead of creating a function and as per html-webpack-plugin 2.30.1 version. Setting chunksSortMode to 'manual' loads the chunks in the same order than in the chunks option.

// The following code will include vendor and app chunks in that particular order.
chunks: ['vendor', 'app'],
chunksSortMode: 'manual',

@humorHan
Copy link

humorHan commented Nov 3, 2017

When I met this problem, I gave the official feedback on why there was no attribute value of'manual', which would be more convenient.
However, the official replied, "I can get the desired results in other ways, so...

But when I saw the new version of the problem, I was very happy, at least to accept the proposal

@heisian
Copy link

heisian commented Dec 14, 2017

@Javierb is it just me or does your snippet not have any effect on the order of:

// Both are ordered as ['app', 'vendor', 'manifest']
compilation.getStats().toJson().chunks;
compilation.getStats().toJson().assetsByChunkName;

I am using:

new HtmlWebpackPlugin({
      inject: true,
      template: './index.html',
      chunks: ['manifest', 'vendor', 'app'], // doesn't seem to do anything?
      chunksSortMode: 'manual', // doesn't seem to do anything?
      ...
});

??

@lock
Copy link

lock bot commented May 31, 2018

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators May 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests