vuejs / vue-cli

🛠️ webpack-based tooling for Vue.js Development
https://cli.vuejs.org/
MIT License
29.76k stars 6.33k forks source link

Add prop in vue.config.js to change vue src directory (copy) #3061

Closed cthames closed 5 years ago

cthames commented 5 years ago

What problem does this feature solve?

I apologize. The previous issue had comments disabled as I was in the middle of responding to the comments by @sodatea and @yyx990803 . There is confusion that I'm trying to address. I'm talking about existing projects see my comment below. I think it's in the best interest and for increased adoption of Vue JS that a thorough discussion from both sides is had instead of ending it prematurely before I even had a chance to respond. I understand wanting to limit for new projects, but existing projects is where greater adoption for Vue JS is. It will also allow for existing projects to transition from another front end to Vue JS slowly without having to re-write an entire app. Businesses aren't going to spend a bunch of money upfront to rewrite an entire app. A slow transition is more feasible.

Feature

Having the Vue src files and directories in the /src directory works for simple projects, but for more complex projects it doesn't work as well. If you're including the Vuejs project in with another project with other programming languages that follow a different or same src dir causes problems. This feature will separate the vue code from the other project code (js/PHP/C#/Go/python/etc.)

Currently if you want to modify the vue src directory you need to modify vue.config.js:

  1. change the alias @ path.

    configureWebpack: {
        resolve: {
            alias: {
            '@': path.join(__dirname, vueSrc)
            }
        }
    }
  2. Use the pages option to change their path:

pages: {
        app_main: {
            entry: path.join(vueSrc, 'main.ts'),
            template: path.join(vueSrc, 'public/index.html'),
            filename: 'index.html',
            title: 'Index'
        }
}

There might be other locations or properties that need to be updated with the change in src directory, but these 2 are the ones I've noticed so far.

There is the public directory that should also be considered. I assume it would also be moved into the specified Vue src directory or made into a separate web.config.js option.

If this is already doable without all the customization mentioned above, let me know.

What does the proposed API look like?

  1. Add an option to vue.config.js called src or vueSrc or vueDir or srcDir or vueSrcDir or sourceDir or whatever is deemed appropriate.
  2. Either assume the public folder is also in the new vueSrc path or create a separate publicSrc (or publicDir) option in vue.config.js.

The value would be starting the current directory so you don't need to include the whole path.

Example: if you wanted to change the src vue directory and files from src to webclient/vue.

Note: The developer would manually create the new webclient directory in the project root. Then rename the src directory to vue and move it into the webclient folder. The public directory would also be moved into webclient/vue.

vue.config.js

module.exports = {
    sourceDir: 'webclient/vue', // Default: /src
    publicDir: 'webclient/vue' // Default: /public
}

Or maybe to keep the future in mind, sourceDir should be contained in projectPaths or vuePaths

vue.config.js

module.exports = {
    vuePaths: {
        sourceDir: 'webclient/vue', // Default: /src
        publicDir: 'webclient/vue' // Default: /public
    }
}

This is NOT something that would make cli-service / webpack move the files automatically.

The vue-cli would then change the vue src path where used by the cli-service.

The 3 places I've seen so far are:

  1. resolve: { alias: { '@': pathToVueSrc } }
  2. pages / entry / template
  3. The public directory would also be located in the pathToVueSrc or another vue.config.js option.

Thanks! Keep up the good work!

vue-bot commented 5 years ago

Hello, your issue has been closed because it does not conform to our issue requirements. In order to ensure every issue provides the necessary information for us to investigate, we require the use of the Issue Helper when creating new issues. Thank you!

cthames commented 5 years ago

@sam3d I think people should change the directory only after having fully understood what he/she's doing.

@sodatea In regards to your comment. That is why there are defaults and the options only need to be mentioned in the docs. The applicability is for existing and complex apps. As well as, existing projects migrating from another front end framework to VueJS.

As @sam3d mentioned there are no cons that I can think of or mentioned by @sodatea or @LinusBorg and is no different than the outputDir and assetsDir options.

I've currently run into this situation with all of the existing apps where I was adding VueJS or upgrading VueJS. If later on you add another feature that requires the src path, then everyone will need to change it. It's better to have it in one place.

Code wise, having it one variable to make these changes is beneficial to all, including to additional vue-cli changes.

Note: As I was commenting to sodatea, yyx990803 added a comment... Here is my response..

@yyx990803 In regards to your comment, I believe greater adoption will happen with VueJS if it wasn't so constrained and hard coded in the src directory (and also public directory).

I disagree with your first point.

  1. The CLI is designed for SPAs or projects that separates front-end from the backend (only communicating via API calls). You can place the Vue CLI project directory anywhere you want - but it should be separate from other code in your entire project. It's not recommended to mix server-side code inside a Vue CLI project root.

Most businesses are not going to start new and re-program all their logic. Nor do only a SPA. Existing projects may already have the src and it's being used by another programming language. Also, the majority of projects are going to have a mix of server-side and VueJS code. This is because they probably already have SSR in another language already built and not with VueJS. This would also allow the business/project to be in a transition state. If they had it this way it may allow them to slowly transition to be only Vue JS.

I would like to point out to point 3.

  1. We want to encourage a somewhat consistent source code structure across all Vue CLI projects so that users have an easier time jumping into a new project.

The defaults will exist no issues with keeping it consistent with new projects. No con here.

Point 3 also seems to indicate a complete disregard and understanding to existing projects. No business is going to rebuild an existing project to fit Vue JS's structure. If you allow it to easily be customized it will lead to greater adoption as well as greater chances of keeping Vue JS up to date with the newest version. A fragmented ecosystem is not in the best interest for Vue JS.

I lastly respectfully disagree with your point 4.

  1. There is a maintenance cost in every feature added. As explained above, we'd rather spend time on features that bring more substantial improvements.

This option(s) easily allow for these changes as well as make it easier for any additional changes to the vue-cli that may require this path. It is set in one place and not hard coded to src. Seems like a no brainer to me, but then I haven't looked at the Vue CLI source code.

BTW @yyx990803 and team keep up the good work with Vue!

sam3d commented 5 years ago

Thank you for taking the time to write that out @cthames, very well articulated! To expand on all of these points, the Vue.js homepage advertises the framework as these two things (among other things):

  1. versatile, and
  2. incrementally adoptable

Point 2 being particularly key here, as this choice seems to go against the nature of incremental adoption that Vue.js strives for (requiring a re-architecting of project structure).

I fully understand and am taking on board all of the points you guys are making (and appreciate you all taking the time to explain your views and standpoints), but this issue honestly seems worth more discussion than you guys have been affording it so far.

sam3d commented 5 years ago

Also @cthames my thoughts on the proposed API is to use:

// vue.config.js
module.exports = {
    sourceDir: "src"
}

Instead of your proposed vueSrcDir or various alternatives for the following reasons:

  1. Better matches the other configuration properties of outputDir and assetsDir,
  2. Doesn't require the inclusion of vue, which is implicit from the purpose of the file,
  3. Doesn't use the potentially legacy folder name src as part of the property, and
  4. Doesn't require weird camelCase usage on the abbreviation Src

Thank you again for taking the time to write up such a thorough proposal 😄

LinusBorg commented 5 years ago

Just a quick note, I reopened this after it was auto-closed because the effort deserves a repl.

I won't have time for that and seeing as Evan already closed the other issue (#3040), I don't think he has much more to say for the moment.

I'll answer tomorrow after getting some sleep.

cthames commented 5 years ago

@sam3d well if @yyx990803 approves I wouldn't mind anyway it's named. However, maybe to keep the future in mind maybe it should be paths.sourceDir or projectPaths.sourceDir or vuePaths.sourceDir, see below.

// vue.config.js
module.exports = {
    vuePaths: { 
        sourceDir: 'src',
        publicDir: 'public'
    }
}

Anyway if it happens I'm happy and maybe so will @gmclp @chanlito, @chrishrtmn, @pdmshrestha, @djsmedes, @Nick-Anderssohn, @azjezz, @dumptyd, @vhanla, @Hippocrate and the 13+ others.

sam3d commented 5 years ago

At least from my end there's honestly no hurry at all.

I understand that as maintainers of a very popular open source project, you guys have to make potentially hard and outwardly controversial choices for feature scope; I just want there to be more dialogue on this issue than the "respond and lock" as all present feedback points towards this being a desired feature.

LinusBorg commented 5 years ago

Just another quick quite general reply so I can sleep without wheels spinning in my head: While you're at it, add the /tests folder to the list, or more precise, one unit test folder, one e2e test folder.

Plus, each of these options would also need a CLI options flag for vue create, as it would otherwise write into these directories that you don't want to, and break stuff.

Maybe you start to see how it's more complex than you think. that's basically why we see it as more useful to integrate the vue-cli project as a subdirectory itself into existing projects.

The existing (usually backend) application won't care where your frontend source and test files are - it usually only cares about where the bundled files end up, which you control with the already existing options (and which is why these options exist)

cthames commented 5 years ago

Quick response (well was a quick response, now a little long) @LinusBorg so I don't forget.

In regards to:

Plus, each of these options would also need a CLI options flag for vue create, as it would otherwise write into these directories that you don't want to, and break stuff.

I realize your comment was quick, so unless I'm missing something...

I think the incremental step and to avoid confusion for vue-cli is to:

  1. implement it to use the options in vue.config.js and then
  2. have it only documented.

So in other words, these options would initially not be apart of the vue create process.

At least for what I'm requesting with this issue. A new Github issue can be created to integrate it into the vue create process and UI (if needed or allowed... I haven't used the UI yet).

The reason for this is:

  1. This would make the user have to change the project structure on their own volition.
  2. This would then enable @yyx990803 enforcement of keeping the Vue JS project structure consistent for new projects and also allow existing projects to make the changes they need so they can slowly transition their app to be completely Vue JS.

I'm speaking from our point of view, but new Vue JS projects typically start off on their own then are integrated into an existing project after a very basic MVP (minimum viable product). This is to get feedback / buy-in into the new front-end project before it becomes apart of the existing project.

How I see the proposed process for existing projects is:

  1. User vue create a new blank project with Vue JS recommended project structure src.
  2. User gets to a very basic MVP (optional)
  3. User changes project structure directories from src to webclient/vue and public to webclient/vue/public
  4. User then updates vue.config.js options vuePaths.sourceDir and vuePaths.publicDir to use new project structure.
  5. User moves Vue JS project files and directories into existing project. (except files that may need to be merged, e.g. package.json, etc.)
  6. Any other changes to accommodate the integration. Changes differ project to project. package.json etc.

This allows us to get a very basic stubbed MVP up going quickly without affecting the existing app and get feedback / buy-in. And then when it reaches a point we can then integrate it and start to transition the old front end piece-by-piece to the new Vue JS front end.

If that proposed process doesn't work please let me know and why it wouldn't work.

LinusBorg commented 5 years ago

My counter-proposal for the process:

  1. User creates /webclient/vue directory
  2. User runs vue create . in this directory
  3. (optional) User copies scripts that he wants in the root of the project to the root folder's package.json (so they don't have to cd into /webclient/vue anymore) - if that even exists.
  4. User installs shared dependencies in the root package,.json and frontend-specific stuff in webclient/vue specific package.json

Seems much simpler and much cleaner.

I admit that /public may still need some adjustment, as assets might come from a shared project dir, though (but already possible with a CopyWepackPlugin).

cthames commented 5 years ago

@LinusBorg if I'm understanding then you would have 2 separate package.json, node_modules, webpack, postcss, etc.

  1. Project Root /package.json
  2. Vue client files /webclient/vue/package.json

If I'm misunderstanding, please let me know.

That would be a developer and project maintenance headache.

We've stayed away from nested npm projects:

  1. Multiple npm package installs / packages / scripts.
  2. Multiple node_modules with hundreds of MB of files duplicated.
  3. Complexity to the build process and maintaining scripts between both.
  4. Complexity to developing and hot reload from the existing project and the vue project. We develop with hot reload working on the existing project site along with our font-end clients which would include Vue. That way only one site is running with all components, mimicking production.
  5. Making sure the same build process is happening for the same assets.
  6. Re-usability between the existing projects front end client files and the new Vue JS client.
  7. Keeping all the npm package versions the same and up-to-date.
  8. etc...

It is much more simple to have everything in one package.json.

I believe there is a misunderstanding dealing with existing projects. It's possible that the existing projects we've integrated Vue JS is completely different. However, I suspect that there might be limited experience of having to integrate Vue JS into existing projects (medium / large / complex projects) where the transition to Vue JS is slow and with limited time available to do the transition to Vue JS. There are more important business processes that will have priority over re-writing the client side to Vue JS.

It sounds like (and I could be wrong / misinterpreting) it is expected for Vue JS to be completely separate and in its own site/process. Unfortunately only large businesses with money to spare would spend the resources (people / time / money / etc) needed to rewrite an app that way. The majority of businesses are not large businesses.

Most businesses have limited resources and are not going to transition fully or in a "all in" situation. There are other priorities in a business. Most businesses are not AirBnB / FB / Twilio / etc.

What I'm not understanding, is why this web.config.js options request is so difficult? Granted I haven't browsed the code.

@LinusBorg @yyx990803 How difficult would it be to:

  1. Expose the /src and /public private variables to the vue.config.js?
  2. vue create process would NOT use or do anything with these options. (this can be a separate discussion and separate GitHub issue)
  3. The UI will also NOT use these options.

If the /src and /public paths are already private variables than exposing them should be rather easy. If they're hard coded then that's another problem, that should be refactored anyways.

I believe that in enabling existing projects to easily integrate Vue JS will lead to higher adoption in existing projects and keeping Vue JS updated to the recent versions, without falling behind.

These vue.config.js options would then make sure any future changes to the path or any additional Vue features that use these paths are incorporated. This will make updating Vue JS in these existing projects so much easier.

It also may turn out that other external Vue JS projects like Nuxt could use them as well, rather than hard coding these values. Keeping the Vue JS ecosystem intact.

Thanks again @LinusBorg for keeping the discussion going. It's nice to learn both sides.

LinusBorg commented 5 years ago

I suspect that there might be limited experience of having to integrate Vue JS into existing projects (medium / large / complex projects) where the transition to Vue JS is slow and with limited time available to do the transition to Vue JS. There are more important business processes that will have priority over re-writing the client side to Vue JS.

Not at all. That's a quite common approach from what we hear - with and without vue-cli. Maybe it's just better to switch to vue-cli when vue plays a more dominant role in the project. Maybe it's better to integrate with the existing build system at first, etc. (speaking generally here, obviously I know nothing about your particular situation).

We've stayed away from nested npm projects: [...]

I don't agree with most of these arguments. yarn's workspaces feature makes it quite easy to keep dependencies in sync across such nested npm projects, while we can keep dependencies seperated when they can be.

But I want to reply on a more general note about the cost of this "small" change.

Cant be that hard, right?

you ask:

How difficult would it be to: Expose the /src and /public private variables to the vue.config.js? [...]

The answer to this is: on its own - not very difficult, clearly. Just change the alias. And the webpack entry.

Or maybe not? tsconfig.json has references to /src, and until today, we never changed files back and forth because of settings in vue.config.json (we only do file changes upon plugin installs with a Generator). So that is something the user has to adjust (if they use Typecript. babel users are fine - yay!), unless we want to write an entire new subsystem for changing such settings on the fly.

We would also not be able to adjust the reference to /src in the jest config for the same reason(even worse, it's a .js file):

  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },

... so now in serve & build aliases work, but in jest they fail. Nice.

And another thing: Are we sure everything works if someone decides to point srcDir to a folder in the tree above our vue-cli project root? Won't eslint fail all of a sudden because there's no config? Should we copy the config around? or tell the user to do so? Other configs might have similar problems, which we would have to think about, try and write tests for. and maintain those tests.

You might say it's ok to only define srcDir as a folder on the same root level, but lots of people won't understand why that limitation exists.

On the other side: If we don't add this little srcDir feature - what does that mean?

Two lines of webpack config do that for you as well (changing entry & webpack alias). The difference when you customise webpack yourself is: Now you take responsibility to make things work with the changes that you want. We clearly state: leaving this structuture is possible, but we don't take responsibility to make it work out of the box for all of the use cases there are.

And that's not the only issue that I have with the request.

Managing Expections and ensuring compatibility

You follow up the question about how hard it would be with assurance that you don't want this in the UI, or represented as a flag in the vue create command, but these will indadvertedly be requests users will raise once we officially "open up" the project for the customisation of source folders (and then test folders, etc).

And those requests would be totally warranted in many ways, because the feature as you request it would essentially make it seem like you can switch the source folder in a central place, but in reality all that we would (and can) change is the @/ alias and the default webpack entrypoint, so it would really be a half-working project.

If we on the other hand implemented a vue create flag, we could change tsconfig.json, and jest.config.js etc. - But now the whole create process is much more complicated.

Then there's the problem that existing third party plugins don't respect the srcDir settting as it doesn't exist yet, and new ones wouldn't be able to, as the Generator is s simple template copy mechanism - you define a tempate file in a /src dir, it's copied to /src, easy as pie. So to make plugins respect this feature, we would have to adjust Generators.

...at this moment you likely will feel the need to tell me that you don't want all that. But other people will, and they will ask us why we added an option that only "half" works. Adding a disclaimer to the docs for such a setting doesn't really make this much better, either.

We want to have clear boundaries what we support and what we we don't, and we only want to add things that work well with all plugins that we deliver out of the box - at a reasonable ratio of "added value vs. added complexity".

That's why we take the stance that the what we deliver out of the box works well if you follow the given project structure. You can break out of it anytime you choose to, but then it's your responsibility to make the pieces that you chose to add to your project work smoothly together.

yyx990803 commented 5 years ago

I think there are two mixed requests here:

Side note: incrementally adoptable means you can use Vue without opting into the CLI. The whole point of the CLI is convention over configuration.

cthames commented 5 years ago

@LinusBorg @yyx990803 Thanks for your reply and information! Much appreciated for your time! We'll continue to make the alias and pages options, as they work for the time being. We were only hoping to make it easier for existing legacy code while in transition.

sam3d commented 5 years ago

@yyx990803 I apologise for pushing so hard on this, but I really appreciate the definitive response. My organisation have already got to work on our own fork that includes this feature, as a large number of our internal projects would benefit from being able to do this. It's good to know that a PR would be considered, so my team and I will make one when we feel it's ready and stable.