dvlden
dvlden

Reputation: 2462

Vue CLI v3 - How does it know what JS files should be chunked in a different file(s)

I am having hard times wrapping my mind around new CLI and configuration. In the official documentation, I couldn't really find anything about CSS and how to add it as an entry point and not import it directly into an component or main.js file.

I realized that some JS files are being chunked into separate file, from main.js and the rest gets compiled where supposed to - into the app.js.

I was wondering, how does it know in the background what should be stored as "vendor" for the JS, but when I try to import some "vendor" SASS files into main.js it does not and it merges all within a single app.css file.


Can anyone tell me, how does one create/modify the vue.config.js and tell the bundler that I also want app.scss to be an entry point and vendor.scss to be another entry point.

I am unsure what are best practices for such purpose, but I always did it this way with my own webpack config...

Partial example below:

entry: {
    vendor: [
        './styles/vendor.scss',
        './scripts/vendor.js'
    ],
    app: [
        './styles/app.scss',
        './scripts/app.js'
    ]
}

EDIT #1

I think I got the first one...

"How does it know what should be chunked in "vendor" files?

What I did not figure out yet is... What if I am having my personal assets/styles/vendor directory where I @import those SASS files from NPM and do some modifications of variables or whatever.

Importing this file to main.js does not get chunked in this case... So there must be a way to tell bundler that I want everything within that directory or everything within vendor.scss file where everything is being imported, to be chunked out.


EDIT #2

I figured I can use WebPack's magical comments to import the main vendor SCSS file, such as:

import(/* webpackChunkName: "vendor" */ './assets/styles/vendor.scss')

I don't have a problem with this, but apparently the bundler does. It generates an empty vendor.[hash].js file as well.


EDIT #3

I did further research and learned that there's a command vue inspect which would output the webpack configuration.

So when making tweaks to vue.config.js, we can look a the output with this command if there's a bug or something is not working as expected.

Further more, I learned that if we specify entry directly in our vue.config.js file, that we will get an error that entry cannot be specified within our configuration file.

The following is forbidden to do so, but it's what I actually want to achieve...

// vue.config.js
module.exports = {
  entry: {
    app: [
      './src/main.js',
      './src/assets/styles/app.scss'
    ],
    vendor: [
      './src/assets/styles/vendor.scss'
    ]
  }
}

The actual proper way to do this will be an answer to my own question...

Upvotes: 3

Views: 553

Answers (1)

dvlden
dvlden

Reputation: 2462

The way to achieve this is by using WebPack's Chain API.

However, if I did everything correctly, I still see a problem of generated vendor.[hash].js file with some WebPack module boilerplate. This JS file is also being injected to the index.html template.

Which leads to the same outcome as the attempt of my EDIT #2, except that we're no longer importing our Sass files within main.js

To modify entry points for my purpose of this question, we can do it the following way:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config
      .entry('app')
        .add('./src/assets/styles/app.scss')
        .end()
      .entry('vendor')
        .add('./src/assets/styles/vendor.scss')
      .end()
  }
}

Note

We're not specifying the app entry JS file, which would be main.js by default, because we're not overriding the current entry point. Instead, we're extending it, so everything works as expected.


UPDATE

Until WebPack resolves this in future major releases, I found a great package - fqborges/webpack-fix-style-only-entries. It solves this issue that I was having and I'd suggest you to use it.

Final configuration would look like this:

const FixStyleOnlyEntries = require('webpack-fix-style-only-entries')

module.exports = {
  chainWebpack: config => {
    config
      .entry('app')
        .add('./src/assets/styles/app.scss')
        .end()
      .entry('vendor')
        .add('./src/assets/styles/vendor.scss')
      .end()
  },

  configureWebpack: {
    plugins: [
      new FixStyleOnlyEntries()
    ]
  }
}

UPDATE #2

After further investigation and use of such configuration for projects, I realized that I had to use !important in styles where I had a need to override anything vendor related.

This is simply because WebPack will inject app, before vendor (both JS and CSS) and it will cause such issue.

Even if we modify the configuration from above and move app entry, below the vendor entry, it will still fail. Reason being, because we're modifying the entry point which already exists by default within vue-cli config. We're adding more entries to the app and we're adding new vendor entry.

To fix this issue of ordering, we must delete the app entirely and then create it ourselves.

const FixStyleOnlyEntries = require('webpack-fix-style-only-entries')

module.exports = {
  chainWebpack: config => {
    config.entryPoints.delete('app')

    config
      .entry('vendor')
        .add('./src/assets/styles/vendor.scss')
      .end()
      .entry('app')
        .add('./src/main.js')
        .add('./src/assets/styles/app.scss')
      .end()
  },

  configureWebpack: {
    plugins: [
      new FixStyleOnlyEntries()
    ]
  }
}

Upvotes: 2

Related Questions