karol-f / vue-custom-element

Vue Custom Element - Web Components' Custom Elements for Vue.js
https://karol-f.github.io/vue-custom-element/
MIT License
1.97k stars 187 forks source link

Environment settings changes #101

Closed Meenakshise closed 6 years ago

Meenakshise commented 6 years ago

Hi Karol,

Basically this is what I do I build the Vue project that emits the app.js, manifest.js and vendor.js files. I refer these files in a different project (I have used Vue Custom Element). In my Vue Project i have an api url which also gets bundled when you build the Vue js file.

module.exports = {
  NODE_ENV: '"production"',
  BASE_URL : '"https://localhost/VueAPI/"'
}

For my development server it is fine. I have also seen the concept of dev and prod.env files. But still i dont think so that will help me. Because we are deploying the built files using octopus. So based upon the deployment server we have to change the config url. How can i achieve this. If i change the config url I need to rebuild and then get the files and once again i have to update the files in the project where i have used right.

karol-f commented 6 years ago

Simplest solution is just check in you Vue component or main.js for something like window.CONFIG and set it using script based on deployment environment.

You can also make some init method in file that register custom elements (Vue.customElement(...)). And register them only if someone will call that init with proper config.

Regards.

Meenakshise commented 6 years ago

But then how do we update the emitted files (which contains the config details) which is already used in the other project.

karol-f commented 6 years ago

@Meenakshise Set config or execute init in other project?

You can also use webpack to generate multiple output with different configs. There are many possibilities - just use what best suits your needs.

Meenakshise commented 6 years ago

ok Karol. Thanks let me try and see what best works for me..

karol-f commented 6 years ago

Feel free to present your solution and maybe ask for directions if sth woun't fit your requirements.

Meenakshise commented 6 years ago

Thank you so much Karol. Definitely i would present it to you before starting my approach.

Meenakshise commented 6 years ago

Hi Karol,

I have 2 projects. One is my Vue UI project and the other is my project (Consuming Project) which actually consumes the emitted js and css files.

module.exports = {
  NODE_ENV: '"production"',
  BASE_URL : '"https://someurl.com/VPVueAPI/"'
}

In team city, I can first build my Vue UI project which will emit the js and css files. I can then copy these files to my other project in the same team city project. This works perfect for the environment which i have specified in my prod.env.js file. And this url is emitted in the app.js file which is already copied to my consuming project. Till here it is fine.

bundleAnalyzerReport:Object({NODE_ENV:"testing",BASE_URL:"https://someurl.com/VPVueAPI/",URL:hello}).npm_config_report}}}).call

When I want to deploy my consuming project to a environment I want the API url to be changed based upon my deployment url as well in the octopus. How can we achieve this? Because the files are already built. We don't want to rebuild again in octopus. Is there any other way.

Meenakshise commented 6 years ago

Or is there a way to separate out the below config file entries from app.js to a separate file named config.json. If it is separated out then we can refer this file also in our consuming project. As part of the octopus deployment we can just update the API url in this json file. Is this possible Karol. Or any suggestions which is possible

({NODE_ENV:"testing",BASE_URL:"https://someurl.com/VPVueAPI/",URL:hello}).npm_config_report}}}).call

karol-f commented 6 years ago

To be honest I don't fully see this.

Regards!

Meenakshise commented 6 years ago

ok no problem Karol. I am trying from my side to see if anything fits. will keep trying :)

Meenakshise commented 6 years ago

I have done this Karol. I created a variable in env.js file like the below. And i am replacing this variable in octopus based upon the deployment server. There is a file substitution variable feature in octopus. With that i am able to replace.

BASE_URL : '"#{WidgetApiUrl}"'

:)

Meenakshise commented 6 years ago

While creating the built files, I need to have a separate js file for each component which is registered as a custom element. How is this achievable. I don't want all the component to be bundled in one app.js file rather i should have customelement1.js, customelement2.js and so on..

Is this possible Karol? I saw the below link But there we are mounting the component to the element which we are not doing. We are just registering the component as custom elements and using that tags in a different page altogether.

https://stackoverflow.com/questions/44984634/webpack-vue-js-and-component-bundles-separation

karol-f commented 6 years ago

In my setup I use lazy load feature of vue-custom-element (https://karol-f.github.io/vue-custom-element/#/demos/lazy-loading) - so the initial bundle is small but when component appear in DOM it will be fetched.

If you have JS files in different domain than the website you might also want to set up __webpack_public_path__ on the fly (https://webpack.js.org/guides/public-path/#on-the-fly).

Regards.

Meenakshise commented 6 years ago

if i consider the 1st option, but still i should have the js script inside my bundle right. If not, from where will it load during lazy load (if the js is not inside my bundle) when i am referring the bundle in a different project altogether.

Did i understood wrongly.

karol-f commented 6 years ago

Hi, what I wrote in above comment is only one option - most popular and well documented solution to your problem - code splitting (using Webpack). I would go that way as it's simplest and most reliable way. Just remember to that you might need to set __webpack_public_path__ (you will know).

karol-f commented 6 years ago

If you show me your code (GitHub repo?) and write about your requirements I can help you tune your app. Regards.

Meenakshise commented 6 years ago

Hi Karol, Thanks for asking. I am working for a company. So i cannot share my github repository. Really sorry. But I can explain the scenario that i am encountering. Let me know if this helps you. If not, i will just create a sample one codepen and will share you the link. https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart It is almost similar to the above link which i mentioned above. I have separate component like component1, component2 and so on.. They are all independent component. But they all consume the store, Http wrapper(axios) for making api calls. And in my main.js (similar to app.js in the example) which is the entry point for the application, i load Vue all the components, vuetify and register the components as custom element in my main.js at the end.

When i build i get 3 files - app.js , manifest.js and vendor.js. The last 2 files should remain the same. Only the app.js should be splitted for each component - one js file and anything that is used for all these components should be splitted in a separate js file (like store or any http wrapper js files). Again in store we have multiple modules. For ex, Shopping Cart component will be only using shopping Cart Module. So it is also good to have this store as part of our component js file itself in certain cases.

Let me know if you have any solution for this Karol.

karol-f commented 6 years ago

Hi, I've prepared sth like this - https://codesandbox.io/s/vmpll1p5w7

Thanks to it, individual widgets are loaded only when they appear on the page.

Regards.

Meenakshise commented 6 years ago

is it possible to split the final bundle into 2 js file. One for product list and one for shopping cart Karol. As i mentioned earlier I will be using this widgets in some other application/Projects. So i would be referring the final bundle in that project. I don't want to put the complete bundle in my layout page. Basically in one page i just need one widget so i can refer only 1 js file in that page instead of my layout page. And in another page i need to use the other widget so i can refer the 2nd bundled js file. How can i achieve this Karol

karol-f commented 6 years ago

If you compile that example from CodeSandbox I gave you (and delete that commented hack in main.js) you will have base, small bundle you could inject on any project. Only after custom elements appear on the page other bundles (only that required) will be loaded - so it's fit into your case.

You could also prepare separate webpack entry points for each widget.

Meenakshise commented 6 years ago

You could also prepare separate webpack entry points for each widget.

This option i already had in my mind Karol. But for each widget i need to create a separate js file. That's why i kept this as my last option and thought of trying.

Let me try what you have told in the sand box in my project and see if it emits a new bundle.

Meenakshise commented 6 years ago

image

I am getting this error with that expression

Object.entries(widgets).forEach(widget => {
  const [name, componentPath] = widget;
  Vue.customElement(name, () =>
    import(componentPath).then(Component => {
      Component.store = store;
      return Component;
    })
  );
});
karol-f commented 6 years ago

ok, my bad - I fixed the example on https://codesandbox.io/s/vmpll1p5w7. Also it doesn't need hack for CodeSandbox anymore.

What is changed - instead of import(componentPath) , we use

import(`./src/components/${componentPath})

Hope it will work now.

karol-f commented 6 years ago

Ok, I've prepared repo based on above CodeSandbox that is working for me - https://github.com/karol-f/vue-custom-element-example-vuex

Meenakshise commented 6 years ago

Thank you so much Karol. In my application it is emitting more than 8 files. I just used 2 widgets. All are emitted with the name as 0,1,2,..8. I think i am using some library files like vue-chart js and vuetify alcarte components. So it is resulted in too many files.

karol-f commented 6 years ago

Hi, some files are probably sourcemaps (that are loaded only if you open Dev Tools), some are vendor and common chunks if you set up CommonChunks plugin. It's not a problem - you don't put them into your page - that files are automatically lazy loaded by your main entry JS file.

Only thing you should do is load main JS file and the rest will be loaded on demand.

Meenakshise commented 6 years ago

ok let me try then. webpack just names them as 0, 1 and so on.. Won't it name them properly with the code it has splitted. Is there a way to do that? image

Should i ignore this warning. Or it has affected my final bundle also?

karol-f commented 6 years ago

Read about chunks naming - you can set structure using chunkfilename in webpack config. To name individually you can use "magic comments" (https://medium.com/faceyspacey/how-to-use-webpacks-new-magic-comment-feature-with-react-universal-component-ssr-a38fd3e296a)

But name is irrelevant to you - you don't load them manually (it woun't work) - they are auto loaded on-demand by your main bundle.

If you want to load it manually use different entry points in webpack config.

Meenakshise commented 6 years ago

Thanks a lot Karol for answering my queries with so much patience :)