Skip to content

"Extracting CSS based on entry" example doesn't work #220

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

Closed
beshanoe opened this issue Jul 26, 2018 · 10 comments
Closed

"Extracting CSS based on entry" example doesn't work #220

beshanoe opened this issue Jul 26, 2018 · 10 comments

Comments

@beshanoe
Copy link

Hello!
I found that the condition in a cacheGroups is never true:

test: (m,c,entry = 'foo') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,

because module object in the recursiveIssuer function doesn't have a name field

function recursiveIssuer(m) {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else if (m.name) { // <----- always undefined
    return m.name;
  } else {
    return false;
  }
}

webpack: 4.16.2
plugin: 0.4.1

@melissa-hong
Copy link

melissa-hong commented Jul 27, 2018

I also had this issue - I logged the object (m) and found the name in this part:

_chunks: 
   SortableSet {
     Chunk {
     id: null,
     ids: null,
     debugId: 1035,
     name: 'base', // <----This is my entry point name
     preventIntegration: false,
     entryModule: [Circular],
     _modules: [Object],
     filenameTemplate: undefined,
     _groups: [Object],
     files: [],
     rendered: false,
     hash: undefined,
     contentHash: {},
     renderedHash: undefined,
     chunkReason: undefined,
     extraAsync: false,
     removedModules: undefined },
     _sortFn: [Function: sortById],
     _lastActiveSortFn: null,
     _cache: undefined,
     _cacheOrderIndependent: undefined },

So I modified the function to this:

function recursiveIssuer(m) {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else {
    for (var chunk of m._chunks) {
      return chunk["name"]
    }
    return false;
  }
}

I'm not sure this is the correct way since it requires accessing a private object but I couldn't figure out another way

@wocaatm
Copy link

wocaatm commented Sep 13, 2018

hi bro, i also do the same thing you do , but i have find a error that Cannot read property 'pop' of undefined

@njgraf512
Copy link

njgraf512 commented Sep 27, 2018

I also had this problem. The solution @melissa-hong suggested did not work for me exactly as written, but it did lead me in the right direction, so thanks for that! I think the problem I had with the stated solution above involved using a for ... of loop with the SortableSet, m._chunks.

A colleague, @hieushift, and I came up with two different solutions that both seem to solve the problem, so hopefully they are helpful to others. I am curious, though, if anyone with more experience with this code could comment on whether or not either of these two work-arounds are particularly good or bad?

Approach 1 (more similar to approach suggested by docs):

UPDATE: This first approach ended up not working. I saw that a css file generated for a different entrypoint was being fetched in the wrong app, and also observed some CSS regressions

Assume app entry point is named app.

function recursiveIssuer(m): {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else {
    return Array.from(m._chunks)[0].name;
  }
}

optimization.splitChunks.cacheGroups: {
  'app-styles': {
    name: 'app-styles',
    test: (m, c, entry = 'app') => {
      return m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry;
    },
    chunks: 'all',
    enforce: true,
  }
}

Approach 2:

No recursive issuer in this approach. Let's assume the name of the entry point is app (same assumption as above).

optimization.splitChunks.cacheGroups: {
  'app-styles': {
    name: 'app-styles',
    test: module => module.constructor.name === 'CssModule',
    chunks: chunk => chunk.name.startsWith('app'),
    enforce: true,
  }
}

I lean towards thinking approach 1 above is slightly better since we arrive directly at the entry point name for an exact equality check, but still curious what others may think.

Note:

We use HTMLWebpackPlugin v3.2.0, and do not automatically inject assets into the html template. For both solutions above, in order to make the generated css chunk available as part of htmlWebpackPlugin.files.css in the plugin, I had to add app-styles to the array of chunks in the HtmlWebpackPlugin config. Perhaps this should be expected, but this also caused an additional Javascript chunk to be injected into the page with the following file contents:

(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);

I'm not too sure how important or unimportant this small chunk is, so any insight on that would be helpful. The HtmlWebpackPlugin inserted this chunk as a script tag above the inlined manifest, which doesn't seem correct, but also doesn't seem to cause problems.

@ahmu001

This comment has been minimized.

@Younghun-Jung
Copy link

It is still issue for me.

@alexander-akait
Copy link
Member

/cc @beshanoe problem still exists?

@beshanoe
Copy link
Author

@evilebottnawi I didn't check yet, but I think so. Even though @njgraf512 suggested some ways to solve it, looks like there's no solid solution yet. And I guess the most confusion is caused by the fact that nobody knows which field of module object to use in order to reliably identify an entrypoint. Cause it's pretty internal to webpack.
Maybe it would be better to move towards a more user-friendly approach and hide implementation details, e.g. generate cacheGroups inside the plugin

@alexander-akait
Copy link
Member

@beshanoe thanks!

Somebody can create minimum reproducible test repo, it is allow to identify what is wrong and how better fix it?

@egemon
Copy link

egemon commented May 29, 2019

UPDATE:
I WAS ABLE to fix the issue creating another cacheGroup for that particular part (previously)

Same issue. Can't create minimum reproducible test repo. Continure investigation

    splitChunks: {
      chunks: 'async',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '&&',
      name: true,
      cacheGroups: {
// =============== THIS PART MADE IT WORK =========== 
        ['weplay-components']: {
          priority: 2,
          test: module => module.context && module.context.includes(name),
          chunks: 'all',
          maxInitialRequests: Infinity,
          maxSize: Infinity,
          minSize: 0,
          name: `npm/custom/weplay-components`,
        },
// =============== END: THIS PART MADE IT WORK =========== 
        mainNodeModule: {
          priority: 1,
          test: /[\\/]node_modules[\\/]/,
          chunks: 'initial',
          maxInitialRequests: Infinity,
          minSize: 10 * 1000,
          name: 'npm/main-sync-chunk',
        },
        asyncNodeModules: {
          priority: 1,
          test: /[\\/]node_modules[\\/]/,
          chunks: 'async',
          maxInitialRequests: Infinity,
          minSize: 1000,
          name(module) {
            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]

            return `npm/async/${packageName.replace('@', '')}`
          },
        },
}

issue

css/npm/async/weplay-components.css
Cannot read property 'pop' of undefined

so basically it just doesn't move out weplay-components.css, it leaves it in npm/main-sync-chunk

@alexander-akait
Copy link
Member

Closing due to inactivity. If somebody have problem with example please open new issue with reproducible example, thanks!

ttys3 added a commit to ttys3/hugo-theme-terminal that referenced this issue May 1, 2020
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

9 participants