Open Grandizer opened 5 years ago
+1, We are also experiencing this issue
Core 3 has removed HMR.
So there is no workaround?
Not at this time, I believe Microsoft is expecting the community to pick up these packages. Very frustrating, if you ask me.
Very frustrating, if you ask me. Not just frustrating, it is a shame to kill such important feature. For me it is a deal breaker to upgrade to 3.0, staying at 2.2 :(
Even if UseWebpackDevMiddleware is obsolate today, not deprecated, it doesn't work. I upgraded to 3.0, and the __webpack_hmr endpoint does nothing. No updates, nor heartbeats. Sad :( Staying at .net core 2.2.
@Grandizer , @kiran94 , @JoshDiDuca , @poganytamastsys I managed to upgrade the project to asp core 3 while maintaining a hot reload using Westwind.AspnetCore.LiveReload , because hot reload from asp core 2.2 under asp core 3 stopped working https://github.com/UseMuse/aspnetcore-Vue-starter clone and run from under the box made a pull request
@UseMuse This is a great start having HMR back. My only concern is that instead of using chunks, it rebuilds the whole main.js, therefore reloading the whole page.
@Grandizer , @kiran94 , @JoshDiDuca , @poganytamastsys, @UseMuse I managed to upgrade the project to asp core 3 while maintaining a hot reload
No, you didn't. WestWind.AspNetCore.LiveReload reloads the entire page whenever any single file it monitors is changed. That is cold reloading, not hot reloading in the normal sense of module replacement within a running page.
Is there any progress? @MarkPieszak
(Updated 20191229) I converted my 2.2 project based on this template to 3.1. It took about two days of toiling, so I'm posting what I did for possible benefit to others. It does not have hot or cold reloading, but the package.json has been modified to always rebuild the files in the wwwroot/dist folder on project build. Sorry about the formatting of the code sections - I could not get it to work as desired.
This requires numerous changes to startup.cs. As others have noted, the hot reloading is deleted from the new DLLs. See my new startup.cs below. Note that it contains extras not needed in a basic project.
`using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting;
namespace Vue2Spa { public class Startup { public IConfiguration Configuration { get; } public IWebHostEnvironment Environment { get; set; } public Startup(IConfiguration configuration, IWebHostEnvironment env) { Configuration = configuration; Environment = env; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //Lots of other project-specific stuff here services.AddControllersWithViews(); //I don't know if this is needed }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//UseWebpackDevMiddleware DELETED in 3.0
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapFallbackToController(
action: "Index",
controller: "Home");
});
}
}
}`
Program.cs `using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting;
namespace Vue2Spa { public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); }
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}`
For some unexplainable reason a section is being shown as code, you'll need to decode it with and online html decoder to show the < and > characters correctly.
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <SpaRoot>ClientApp\</SpaRoot> <Dist>wwwroot\dist\</Dist> <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules**</DefaultItemExcludes> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="3.1.0" /> <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.4.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.4.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.0" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.0" /> <PackageReference Include="Serilog" Version="2.9.0" /> <PackageReference Include="Serilog.AspNetCore" Version="3.2.0" /> <PackageReference Include="Serilog.Sinks.File" Version="4.1.0" /> </ItemGroup>
<ItemGroup> <!-- Files not to show in IDE --> <None Remove="yarn.lock" /> <!-- Don't publish the SPA source files, but do show them in the project files list --> <Content Remove="$(SpaRoot)" /> <None Remove="$(SpaRoot)" /> <None Include="$(SpaRoot)" Exclude="$(SpaRoot)node_modules\" /> </ItemGroup>
<ItemGroup> <ProjectReference Include="..\TaskManagers\TaskManagers.csproj" /> </ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') "> <!-- Ensure Node.js is installed --> <Exec Command="node --version" ContinueOnError="true"> <Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> </Exec> <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." /> <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" /> </Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish"> <!-- As part of publishing, ensure the JS resources are freshly built in production mode --> <Exec Command="node -e "console.log('NPM Installing dependencies...')"" /> <Exec WorkingDirectory="$(SpaRoot)" Command="npm install --ignore-scripts" /> <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(Dist)**; $(SpaRoot)dist\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<!-- I don't know if the next line is needed -->
<!-- <ExcludeFromSingleFile>true</ExcludeFromSingleFile> -->
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
npm install --save-dev mini-css-extract-plugin
Delete const ExtractTextPlugin = require('extract-text-webpack-plugin') Add const MiniCssExtractPlugin = require('mini-css-extract-plugin')
Delete const extractCSS = new ExtractTextPlugin('site.css') Add const extractCSS = new MiniCssExtractPlugin('site.css')
Update rule for css Old module: { rules: [ { test: /.css$/, use: isDevBuild ? ['style-loader', 'css-loader'] : ExtractTextPlugin.extract({ use: 'css-loader' }) }, New rules: [ { test: /.css$/, use: isDevBuild ? ['style-loader', 'css-loader'] : [MiniCssExtractPlugin.loader, 'css-loader'] },
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = () => { const extractCSS = new MiniCssExtractPlugin('vendor.css')
module: {
rules: [
{ test: /\.css(\?|$)/, use: [MiniCssExtractPlugin.loader, 'css-loader'] }
return [{ mode: isDevBuild ? 'development' : 'production', devtool: false, // IMPORTANT: without this statement, the source map is not correctly built using SourceMapDevToolPlugin
6, (Optional) Update to use FontAwesome 5. a. In Visual Studio, Solution Explorer, Project file listing, Dependencies, npm: uninstall all existing fortawesome items
b. Install the latest npm packages $ npm i --save @fortawesome/fontawesome-svg-core $ npm i --save @fortawesome/free-solid-svg-icons $ npm i --save @fortawesome/free-brands-svg-icons $ npm i --save @fortawesome/free-regular-svg-icons $ npm i --save @fortawesome/vue-fontawesome
c. Modify icons.js to use the new standards. The code sample shows individual icons being added. The new version has a tree-shaking feature which I didn't fully understand, but may allow you to just link to the library. Reference https://github.com/FortAwesome/vue-fontawesome/blob/master/UPGRADING.md https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4 `import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { library } from '@fortawesome/fontawesome-svg-core'
//These commands import libraries. It is not known if "tree-shaking" will remove the unused icons so that only used icons are included import { fas } from '@fortawesome/free-solid-svg-icons' import { faBrands } from '@fortawesome/free-brands-svg-icons'
//The following commands import specific icons import { faFontAwesome } from '@fortawesome/free-brands-svg-icons/faFontAwesome' import { faMicrosoft } from '@fortawesome/free-brands-svg-icons/faMicrosoft' import { faVuejs } from '@fortawesome/free-brands-svg-icons/faVuejs'
library.add(faFontAwesome, faMicrosoft, faVuejs)
import { faHome } from '@fortawesome/free-solid-svg-icons/faHome' import { faList } from '@fortawesome/free-solid-svg-icons/faList' import { faGraduationCap } from '@fortawesome/free-solid-svg-icons/faGraduationCap' import { faSpinner } from '@fortawesome/free-solid-svg-icons/faSpinner' import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons/faExclamationTriangle' import { faCog } from '@fortawesome/free-solid-svg-icons/faCog' import { faCheckSquare } from '@fortawesome/free-solid-svg-icons/faCheckSquare' import { faTimesCircle } from '@fortawesome/free-solid-svg-icons/faTimesCircle' import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck' import { faAngleUp } from '@fortawesome/free-solid-svg-icons/faAngleUp'
library.add(faHome, faList, faGraduationCap, faSpinner, faExclamationTriangle, faCog, faCheckSquare, faTimesCircle, faCheck, faAngleUp )
export { FontAwesomeIcon } `
package.json The main change to get the single file components to update on build is "install": "npm run build-vendor:dev && npm run build:dev" I updated the version number of numerous packages. The babel update is definitely needed, and fontawesome updates may be needed. I don't know if the other updates are needed, but they don't do any harm.
{ "name": "aspnetcore-vuejs", "description": "ASP.NET Core & VueJS Starter project", "author": "Mark Pieszak", "repository": { "url": "https://github.com/MarkPieszak/aspnetcore-Vue-starter" }, "license": "MIT", "scripts": { "dev": "cross-env ASPNETCORE_ENVIRONMENT=Development NODE_ENV=development dotnet run", "build": "npm run build-vendor:prod && npm run build:prod", "build:prod": "cross-env NODE_ENV=production webpack --progress --hide-modules", "build:dev": "cross-env NODE_ENV=development webpack --config webpack.config.js --progress", "build-vendor:prod": "cross-env NODE_ENV=production webpack --config webpack.config.vendor.js --progress", "build-vendor:dev": "cross-env NODE_ENV=development webpack --config webpack.config.vendor.js --progress", "lint": "eslint -c ./.eslintrc.js ClientApp//*.js ClientApp/*/.vue ClientApp//.json webpack.js", "install": "npm run build-vendor:dev && npm run build:dev" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.26", "@fortawesome/free-brands-svg-icons": "^5.12.0", "@fortawesome/free-regular-svg-icons": "^5.12.0", "@fortawesome/free-solid-svg-icons": "^5.12.0", "@fortawesome/vue-fontawesome": "^0.1.9", "axios": "^0.15.3", "core-js": "^2.5.3", "element-ui": "^2.4.4", "vue": "^2.6.11", "vue-router": "^3.1.3", "vue-server-renderer": "^2.6.11", "vue-template-compiler": "^2.6.11", "vuex": "^3.1.2", "vuex-router-sync": "^5.0.0" }, "devDependencies": { "aspnet-webpack": "^2.0.3", "babel-core": "^6.26.3", "babel-eslint": "^10.0.3", "babel-loader": "^7.1.5", "babel-plugin-transform-async-to-generator": "^6.24.1", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-es2015": "^6.24.1", "babel-preset-stage-2": "^6.24.1", "babel-register": "^6.26.0", "bootstrap": "^4.0.0", "cross-env": "^3.2.4", "css-loader": "^0.26.4", "eslint": "^4.18.2", "eslint-config-standard": "^11.0.0", "eslint-plugin-html": "^4.0.2", "eslint-plugin-import": "^2.9.0", "eslint-plugin-node": "^6.0.1", "eslint-plugin-promise": "^3.7.0", "eslint-plugin-standard": "^3.0.1", "event-source-polyfill": "0.0.7", "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^0.9.0", "font-awesome": "^4.7.0", "jquery": "^2.2.4", "mini-css-extract-plugin": "^0.9.0", "node-sass": "^4.8.2", "optimize-css-assets-webpack-plugin": "^1.3.2", "popper.js": "^1.14.1", "sass-loader": "^4.1.1", "style-loader": "^0.13.2", "url-loader": "^0.5.9", "vue-loader": "^14.2.2", "webpack": "^4.41.4", "webpack-cli": "^3.3.10", "webpack-dev-middleware": "^3.7.2", "webpack-hot-middleware": "^2.25.0" } }
After these changes, a project build will launch a full run of npm, which will update the single file components. As an alternative, you can change the install script item in package.json to remove the npm run and manually rebuild the single file components. Of course, this is not hot reloading. But it does allow development work to proceed.
For manual rebuilding: At a powershell command prompt at the root of the project, Run the following to update main.js and main.js.map
$ npm build:dev
To update vendor.js, vendor.css and vendor-manifest.json, run
$ npm build-vendor:dev
Actually, there's a way to make the hot-reload works. It require to use the spa.UseProxyToSpaDevelopmentServer("http://localhost:8080");
line under the app.UseSpa(...=> { //somewhere here
I did it on my current VueJS starter (different repository than this using picnic css instead of bootstrap). However, it requires you normally to start the VueJS project using WebPack outside of Visual Studio using let's say webpack-dev-server
. The proxy will link between your webpack port (http...8080) and your webapp on port 5000/5001. That being said, if you start your application using HTTPS in development, it will fails since the certificate used in your application is not valid and the Spa-PROXY will not like it (So far I've seen no option to do skip that validation). You could still share the same SSL certificate (pfx, etc.) and make it work using SSL locally. Personally, I've removed the HTTPS for local and use HTTP + Proxy using webpack-dev-server
.
In order to avoid running the webpack-dev-server everytime, you could lazilly start a BackgroundService in C#. The caveat with that is that if you push the Stop/Restart button in the IDE it kills the C# application, but does not terminate properly the sub-process tree (current bug: https://github.com/aspnet/AspNetCore/issues/5204). If you use the ctrl
-c
in order to stop your application, it works like a charm.
update: Issue https://github.com/dotnet/aspnetcore/issues/5204 was fixed today 31st of jan. 2020 🎉
+1 I'm also looking to use this template but keen to start from a net core 3.0/3.1 base.
@Nordes the problem with that approach is to completely leave the MVC Razor pages completely. Which I wouldn't agree with. With SPA, trying to handle requests and things over the network is WAY more complex than it needs to be, and that complexity grows quickly. Some people won't be up for that. When using MVC views, I have very simple configs to handle auths, and there are nice Authorize decorators I use to wrap each view, to go completely JS in that manner would be a huge pain for me and other devs who wants to have nicer options of turning it off.
However, I do agree with you that developing a SPA is very easy, and it includes hot-reloading. In my case, I derailed a bit away from this GitHub project's template. First, I began using Vue-CLI as it abstracts away a lot of Vue stuff from webpack. In fact, I favor this approach than straight-up using webpack because the Vue-CLI config brings in a lot of things to aid in your Vue development that you would have had to otherwise set up in your webpack. Take a look at a vue.config.js file and compare that to what you see in webpack.config.js setting up Vue, you'll know straight away which is simpler.
Vue-CLI creates a lot of files that you'd need to set up a location for. In order to get what I had working with Razor, I needed to create two separate environments in launchSettings. One is to use the Vue-CLI dev server - without controllers, and the other is to use IIS Express with controllers set up.
It was a bit messy because I took the generated index.html that Vue-cli created (it brings in the js and CSS that Vue-CLI bundled and compiled). I converted it into a string, sanitized it as much as I could, and then dumped it into my index.cshtml.
When I have time, I'll take the template from this github project, and convert it the same way I did with my project, and I'll add it to my github repo.
Any news upgrading this template to 3.x with hmr?
I've been trying to get HMR working in our .Net Core 3.1+Vue project that was based on an earlier version of this starter template.
It would appear that UseWebpackDevMiddleware isn't gone, it's just moved into the Microsoft.AspNetCore.SpaServices.Extensions nuget package. I downloaded the current code, added that package, added "options => options.EnableEndpointRouting = false" to the services.AddMvc constructor in Startup.cs, updated the project to 3.1 and everything compiled. Any changes I make appear to trigger webpack to recompile. The only thing that doesn't seem to work is that the browser doesn't automatically refresh but if I refresh manually I see the changes. I'm going to try and see if that's fixable but even so it's better than a full recompile of our .NET project.
You can use my forked repo if you want. It works on ASP Core 3.1. It's a bit hacky because I glued the VUE-CLI to MVC. You can see how hacky it is when you see that I basically did a straight-up html injection of the generated index.html outputted by VUE-CLI into an MVC view cshtml file. Because I'm using VUE-CLI, there are no webpack dependencies. And yes, hot-reload works using the VUE-CLI dev server. I tried my best to give instructions on how it works and how to configure it to your liking because I wanted it to be as flexible as possible. It is also being used in my client's production environment.
If you want, you could turn off ever using MVC, meaning no controllers or views. I needed it as the project I was working on had server-side security features I needed to implement.
I should probably break up the code to reflect that, how to have it work with MVC and how to make it work just by using the VUE-CLI
I happened to drop by parachute here when I was trying to find an easier way for the aspnet-core to run JS code "directly", iow, I want to call functions in JS, and needed some kind of bi-directional interop layer.
I guess I'm going to keep using 2 Webpacks, one to server-side render, and the other to client-side render, and some unwieldy bunch of crap code that taps into Webpack's internals and do some shenanigans.
You can control both "instances" of webpack running in the same node, and do some hacks when they are running. The code to start them is something like this:
warning: contains javascript
The only thing that saved me the effort of having to fix this crap was https://fable.io/
As my code is F#, I can just run it directly inside node
, and don't actually need the interop layer.
I was just doing this experiment on getting rid of webpack, I guess I won't then.
At least Blazor is supposed to implement packing and bundling, then all they need to actually do, if they are that committed to support Blazor is to write something that converts Javascript to C#, this would be immensely useful. (not in that specific case I have, I would need to convert C# to F#, but that's another project of mine, lets call it "transposing", as in music) My company is specialized in that kind of thing, source-source conversion, I could do that kind of thing, and make JS->C# compilation, I only need some small financial investment to start it, if someone needs it, that be.
I'm not going to migrate to Blazer for that, heck, I'll write my own webpacker in F#, its easier. How hard could it be, Accorn parser to AST, some treeshaking, babelifying and then some terser library, who needs all those chunk separation complexity anyway, its just a matter of adding some tags to the code and doing tree deforestation, as they call it.
Found this https://github.com/Taritsyn/JavaScriptEngineSwitcher/ Looks like a good replacement for this feature.
I am attempting to upgrade my app to Core 3 and am running into this issue.