Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Webpack Improvements #2

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

Merged
merged 6 commits into from
Mar 31, 2021
Merged

Webpack Improvements #2

merged 6 commits into from
Mar 31, 2021

Conversation

rigor789
Copy link
Member

@rigor789 rigor789 commented Nov 21, 2020

tl;dr A new and simpler webpack config file:

const webpack = require('@nativescript/webpack')

module.exports = env => {
    // initialize @nativescript/webpack with the environment
    webpack.init(env)

    // Optional: specify base config - defaults to auto-discovery
    webpack.useConfig('vue')

    // Optional: apply changes to the internal config using webpack-chain
    // The options object is optional
    const options = {
        order: 10 // execute "last"
    }
    webpack.chainWebpack((config, env) => {
        config.mode('production') // for example: force production mode
    }, options)

    // Optional: merge options into the internal config
    webpack.mergeWebpack({
        something: true
    })
    // or pass a function that returns an object
    webpack.mergeWebpack((env) => {
        return {
            something: true
        }
    })

    // Optional: resolve a new instance of the chainable config
    // Note: this always returns a new instance of the config
    const config = webpack.resolveChainableConfig()

    // resolve a config object that webpack understands
    // Optionally pass in a chainable config 
    // (from `webpack.resolveChainableConfig()` for example)
    // to be used, rather than creating a new instance
    return webpack.resolveConfig()
}

Rendered

@cla-bot cla-bot bot added the cla: yes label Nov 21, 2020
@NathanaelA

This comment was marked as abuse.

@rigor789
Copy link
Member Author

@NathanaelA

  1. Not in the current draft, but it's definitely possible due to the way it works internally:
    1. Dependencies are scanned for a nativescript.config.js
    2. If found, it's called and added to the "apply queue" - (currently pushed into it, but I'll think of an api to control the order too)
    3. Final step is the call to resolveConfig this is the point where everything is actually applied - nothing prior to this call is executed (the chain callbacks, or the merge callback)

Now this does bring up another question, would a simple flag like "last: true" be enough? What happens if multiple plugins want to be applied "last"? Right now the order in which the configs are applied are based on the order in package.json (ie, we are not sorting them, just looping through them).

  1. Not entirely sure what you mean, as this sounds something that the CLI needs to be aware of and handle differently?

@NathanaelA

This comment was marked as abuse.

@rigor789
Copy link
Member Author

Updated RFC with chainWebpack options spec.

@NathanaelA I only implemented last: true - do you have a case where you see fist: true being useful? I couldn't think of one.

@NathanaelA

This comment was marked as abuse.

@NathanaelA

This comment was marked as abuse.

@edusperoni
Copy link

About ordering and stuff. I'd really prefer a priority based approach. 100 by default and plugins can add before-prepare hooks that add their own chain calls (or a property in the package.json).

This chain can then be passed along to webpack.config.js and the developer can, for example, choose to change order, add their own calls somewhere in the middle.

Something like:

module.exports = env => {
    // initialize @nativescript/webpack with the environment
    webpack.init(env);

    // Optional: specify base config - defaults to auto-discovery
    webpack.useConfig('vue')

   // Optional: eject chains: these need to be handled by the developer from now on
   const chains = webpack.ejectChain();
   // Option 1: manually add all chains in whatever order
   chains.forEach((chain) => {
    chain.name; // plugin/core defined name
    chain.priority; // number defining the order
    chain.call; // actual function call
    webpack.chainWebpack(chain.call);
   });
   // Option 2: reinject the chain (you can also add your own)
   webpack.injectChains(chain);

    // Optional: apply changes to the internal config using webpack-chain
    // The options object is optional
    const options = {
        priority: 10 // execute fairly early, as the default is 100
    }
    webpack.chainWebpack((config, env) => {
        config.mode('production') // for example: force production mode
    }, options)

    // Optional: merge options into the internal config
    webpack.mergeWebpack({
        something: true
    })
    // or pass a function that returns an object
    webpack.mergeWebpack((env) => {
        return {
            something: true
        }
    })

    // Optional: resolve a new instance of the chainable config
    // Note: this always returns a new instance of the config
    const config = webpack.resolveChainableConfig()

    // resolve a config object that webpack understands
    // Optionally pass in a chainable config 
    // (from `webpack.resolveChainableConfig()` for example)
    // to be used, rather than creating a new instance
    return webpack.resolveConfig()
}

In the plugin's webpack.chain.js (referenced somewhere, either in hook or package.json):

const chain = [ { call: (config, env) => { .... }, name: 'My nice chain that has to go first!", priority: -10 }, { call: (config, env) => { .... }, name: 'other chain that has no order requirement!" }]
module.exports = chain;

@farfromrefug
Copy link
Collaborator

Wouldn't it be better to say like i want to run before main config ? Like saying run before or after defined config name.
I feel like priority is always going to end up failing. Iike one plugin will put -100000000. And then after that another one will say i want to be first and use a smaller value .... and so on.
I feel like using keys for "configs" and saying before:["main", "vue"] would work better. You would always be sure you are run when you actually want it. And the @nativescript/webpack can handle the order after that.

@rigor789
Copy link
Member Author

I think it's easy to get carried away, and the first pass should just have the simpler priority/order option, which should suffice for 99.999% of the use-cases.

The primary use-case for even specifying the priority/order option is for related plugins to ensure they incrementally apply their desired changes, just like @NathanaelA's example with sqlite & sqlite-commercial.

My understanding is that all these plugins really need to do in the webpack config is adding new copy rules like **/*.sqlite, and additional externals.

With that in mind, let's see how this concrete example would work:

// sqlite/nativescript.config.js

module.exports = webpack => {
  // we probably want to add a helper like this, as it's common enough
  // (the API/signature I need to think through, but had this on my mind for a while)
  webpack.addCopyRule('**/*.sqlite')

  webpack.chainWebpack((config) => {
    // appears that webpack-chain doesn't have the nice syntax for externals yet (there's a pending issue)
    // so we have to spread the existing ones along with our additions. Not pretty, but works.
    config.externals([
       ...config.get('externals'),
       'sqlite-commercial'
    ])
  }, { order: 1 })
}
// sqlite-commercial/nativescript.config.js

module.exports = webpack => {
  webpack.chainWebpack((config) => {
    // this plugin only has to remove itself from externals
    // again, no pretty api from webpack-chain for this yet, but this looks reasonable
    config.externals(
      config.get('externals').filter(external => external !== 'sqlite-commercial')
    )
  }, { order: 2 })
}

This should be fine even if there are multiple plugins with order:1 and order:2 because all we really care in this case is that sqlite is executed before sqlite-commercial any other plugins in between are irrelevant.

I'll experiment with this - and update the spec/RFC based on the feedback, but I wouldn't go further than this.

If down the line we find legitimate use-cases where this is limiting, we can revisit and expose additional methods for altering the ordering without breaking changes.

@rigor789
Copy link
Member Author

rigor789 commented Dec 1, 2020

Updated RFC with the order changes and added some more details how it works internally.

@rigor789 rigor789 merged commit 7c1ab86 into NativeScript:main Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants