├── .github └── workflows │ ├── codeql-analysis.yml │ └── ossar-analysis.yml ├── .gitignore ├── .idea └── .idea.AspDotnetVueJs │ └── .idea │ ├── codeStyles │ └── codeStyleConfig.xml │ ├── dictionaries │ └── highlander.xml │ ├── encodings.xml │ ├── indexLayout.xml │ ├── inspectionProfiles │ └── Project_Default.xml │ ├── jsLibraryMappings.xml │ ├── jsLinters │ └── eslint.xml │ ├── misc.xml │ ├── reactTemplatesPlugin.xml │ ├── vagrant.xml │ └── vcs.xml ├── AspDotnetVueJs.nuspec ├── AspDotnetVueJs.sln ├── CodeStyle.xml ├── LICENSE ├── README.md ├── appveyor.yml └── content ├── .babelrc ├── .dockerignore ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .template.config └── template.json ├── AspDotnetVueJs.csproj ├── ClientApp ├── app.js ├── build │ ├── base.config.js │ ├── publishingLoader.html │ └── webpack.config.js ├── components │ ├── App.vue │ ├── elements │ │ ├── CounterDisplay.vue │ │ └── DataTable.vue │ ├── layouts │ │ ├── CardContainer.vue │ │ ├── HeaderLayout.vue │ │ └── ViewLayout.vue │ └── views │ │ ├── Counter.vue │ │ ├── Home.vue │ │ ├── NotFound.vue │ │ └── WeatherForecast.vue ├── favicon.ico ├── icons.js ├── index.html ├── models │ └── WeatherForecast.js ├── router │ ├── index.js │ └── routes.js ├── services │ └── forecast-service.js ├── static │ └── ie-polyfill.min.js ├── store │ ├── index.js │ ├── modules │ │ ├── counter.js │ │ └── weather.js │ └── mutation-types.js ├── styles │ ├── base │ │ ├── global.sass │ │ └── normalize.scss │ ├── main.sass │ ├── tools │ │ └── variables.sass │ └── vendors │ │ └── element.scss └── utils │ └── helpers │ ├── functions.js │ ├── notification.js │ ├── table-column-composer.js │ └── vuex-logger.js ├── Controllers └── WeatherController.cs ├── Dockerfile ├── Extensions └── ServiceCollectionExtensions.cs ├── Models └── WeatherForecast.cs ├── Program.cs ├── Properties └── launchSettings.json ├── Providers ├── IWeatherProvider.cs └── WeatherProviderFake.cs ├── Startup.cs ├── appsettings.Development.json ├── appsettings.json ├── package.json └── wwwroot └── .gitkeep /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '17 15 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'csharp', 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.github/workflows/ossar-analysis.yml: -------------------------------------------------------------------------------- 1 | # This workflow integrates a collection of open source static analysis tools 2 | # with GitHub code scanning. For documentation, or to provide feedback, visit 3 | # https://github.com/github/ossar-action 4 | name: OSSAR 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | # The branches below must be a subset of the branches above 11 | branches: [ master ] 12 | schedule: 13 | - cron: '24 16 * * 6' 14 | 15 | jobs: 16 | OSSAR-Scan: 17 | # OSSAR runs on windows-latest. 18 | # ubuntu-latest and macos-latest support coming soon 19 | runs-on: windows-latest 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v2 24 | 25 | # Ensure a compatible version of dotnet is installed. 26 | # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201. 27 | # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action. 28 | # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped. 29 | # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action: 30 | # - name: Install .NET 31 | # uses: actions/setup-dotnet@v1 32 | # with: 33 | # dotnet-version: '3.1.x' 34 | 35 | # Run open source static analysis tools 36 | - name: Run OSSAR 37 | uses: github/ossar-action@v1 38 | id: ossar 39 | 40 | # Upload results to the Security tab 41 | - name: Upload OSSAR results 42 | uses: github/codeql-action/upload-sarif@v1 43 | with: 44 | sarif_file: ${{ steps.ossar.outputs.sarifFile }} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | 5 | VueJs.Picnic.CSharp/wwwroot/**/* 6 | VueJs.PicnicTable.CSharp/wwwroot/**/* 7 | 8 | ## Personal temp folder 9 | tmp/**/* 10 | pack_template/**/* 11 | 12 | ## Others 13 | # /Properties/launchSettings.json 14 | 15 | ## Ignore Visual Studio temporary files, build results, and 16 | ## files generated by popular Visual Studio add-ons. 17 | 18 | # User-specific files 19 | *.suo 20 | *.user 21 | *.userosscache 22 | *.sln.docstates 23 | 24 | # User-specific files (MonoDevelop/Xamarin Studio) 25 | *.userprefs 26 | 27 | # Build results 28 | [Dd]ebug/ 29 | [Dd]ebugPublic/ 30 | [Rr]elease/ 31 | [Rr]eleases/ 32 | x64/ 33 | x86/ 34 | bld/ 35 | bin/ 36 | Bin/ 37 | obj/ 38 | Obj/ 39 | 40 | # Visual Studio 2015 cache/options directory 41 | .vs/ 42 | /wwwroot/dist/** 43 | 44 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235 45 | !/wwwroot/dist/_placeholder.txt 46 | 47 | /yarn.lock 48 | 49 | # MSTest test Results 50 | [Tt]est[Rr]esult*/ 51 | [Bb]uild[Ll]og.* 52 | 53 | # NUNIT 54 | *.VisualState.xml 55 | TestResult.xml 56 | 57 | # Build Results of an ATL Project 58 | [Dd]ebugPS/ 59 | [Rr]eleasePS/ 60 | dlldata.c 61 | 62 | # DNX 63 | project.lock.json 64 | artifacts/ 65 | 66 | *_i.c 67 | *_p.c 68 | *_i.h 69 | *.ilk 70 | *.meta 71 | *.obj 72 | *.pch 73 | *.pdb 74 | *.pgc 75 | *.pgd 76 | *.rsp 77 | *.sbr 78 | *.tlb 79 | *.tli 80 | *.tlh 81 | *.tmp 82 | *.tmp_proj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # TFS 2012 Local Workspace 110 | $tf/ 111 | 112 | # Guidance Automation Toolkit 113 | *.gpState 114 | 115 | # ReSharper is a .NET coding add-in 116 | _ReSharper*/ 117 | *.[Rr]e[Ss]harper 118 | *.DotSettings.user 119 | 120 | # JustCode is a .NET coding add-in 121 | .JustCode 122 | 123 | # TeamCity is a build add-in 124 | _TeamCity* 125 | 126 | # DotCover is a Code Coverage Tool 127 | *.dotCover 128 | 129 | # NCrunch 130 | _NCrunch_* 131 | .*crunch*.local.xml 132 | nCrunchTemp_* 133 | 134 | # MightyMoose 135 | *.mm.* 136 | AutoTest.Net/ 137 | 138 | # Web workbench (sass) 139 | .sass-cache/ 140 | 141 | # Installshield output folder 142 | [Ee]xpress/ 143 | 144 | # DocProject is a documentation generator add-in 145 | DocProject/buildhelp/ 146 | DocProject/Help/*.HxT 147 | DocProject/Help/*.HxC 148 | DocProject/Help/*.hhc 149 | DocProject/Help/*.hhk 150 | DocProject/Help/*.hhp 151 | DocProject/Help/Html2 152 | DocProject/Help/html 153 | 154 | # Click-Once directory 155 | publish/ 156 | 157 | # Publish Web Output 158 | *.[Pp]ublish.xml 159 | *.azurePubxml 160 | # TODO: Comment the next line if you want to checkin your web deploy settings 161 | # but database connection strings (with potential passwords) will be unencrypted 162 | *.pubxml 163 | *.publishproj 164 | 165 | # NuGet Packages 166 | *.nupkg 167 | # The packages folder can be ignored because of Package Restore 168 | **/packages/* 169 | # except build/, which is used as an MSBuild target. 170 | !**/packages/build/ 171 | # Uncomment if necessary however generally it will be regenerated when needed 172 | #!**/packages/repositories.config 173 | 174 | # Microsoft Azure Build Output 175 | csx/ 176 | *.build.csdef 177 | 178 | # Microsoft Azure Emulator 179 | ecf/ 180 | rcf/ 181 | 182 | # Microsoft Azure ApplicationInsights config file 183 | ApplicationInsights.config 184 | 185 | # Windows Store app package directory 186 | AppPackages/ 187 | BundleArtifacts/ 188 | 189 | # Visual Studio cache files 190 | # files ending in .cache can be ignored 191 | *.[Cc]ache 192 | # but keep track of directories ending in .cache 193 | !*.[Cc]ache/ 194 | 195 | # Others 196 | ClientBin/ 197 | ~$* 198 | *~ 199 | *.dbmdl 200 | *.dbproj.schemaview 201 | *.pfx 202 | *.publishsettings 203 | orleans.codegen.cs 204 | 205 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235 206 | /node_modules/** 207 | !/node_modules/_placeholder.txt 208 | 209 | # RIA/Silverlight projects 210 | Generated_Code/ 211 | 212 | # Backup & report files from converting an old project file 213 | # to a newer Visual Studio version. Backup files are not needed, 214 | # because we have git ;-) 215 | _UpgradeReport_Files/ 216 | Backup*/ 217 | UpgradeLog*.XML 218 | UpgradeLog*.htm 219 | 220 | # SQL Server files 221 | *.mdf 222 | *.ldf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | 238 | # Visual Studio 6 build log 239 | *.plg 240 | 241 | # Visual Studio 6 workspace options file 242 | *.opt 243 | 244 | # Visual Studio LightSwitch build output 245 | **/*.HTMLClient/GeneratedArtifacts 246 | **/*.DesktopClient/GeneratedArtifacts 247 | **/*.DesktopClient/ModelManifest.xml 248 | **/*.Server/GeneratedArtifacts 249 | **/*.Server/ModelManifest.xml 250 | _Pvt_Extensions 251 | 252 | # Paket dependency manager 253 | .paket/paket.exe 254 | 255 | # FAKE - F# Make 256 | .fake/ 257 | 258 | .vscode/ 259 | /content/wwwroot 260 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/dictionaries/highlander.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | paiva 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/jsLinters/eslint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 12 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/reactTemplatesPlugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/vagrant.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/.idea.AspDotnetVueJs/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AspDotnetVueJs.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aspdotnet-vuejs 5 | Highlander Paiva 6 | hvpaiva 7 | 8 | Template for ASP.NET Core 2.2 WebApi + Vue.js Client app with webpack and hot reloading 9 | 10 | 11 | 12 | 13 | {{version}} 14 | 15 | https://github.com/hvpaiva/aspdotnet-vuejs 16 | https://github.com/hvpaiva/aspdotnet-vuejs/blob/master/LICENSE 17 | web template vuejs aspnet dotnet webapi vuex elementui 18 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /AspDotnetVueJs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspDotnetVueJs", "content\AspDotnetVueJs.csproj", "{8F165E5B-8BA1-4858-B79F-C2FE04050F42}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /CodeStyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 12 | 13 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 36 | 37 | 38 | 74 | 75 | 76 | 80 | 81 | 82 | 83 | 87 | 88 | 89 | 90 | 93 | 94 | 95 | 96 | 99 | 100 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Highlander Paiva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NuGet](https://img.shields.io/nuget/v/aspdotnet-vuejs.svg)](https://www.nuget.org/packages/aspdotnet-vuejs/) 2 | [![Build status](https://ci.appveyor.com/api/projects/status/kutcm6fkukd1cx71/branch/master?svg=true)](https://ci.appveyor.com/project/hvpaiva/aspdotnet-vuejs/branch/master) 3 | 4 | # Dotnet Core 3.0 + VueJs 5 | 6 | This project main idea is to provide an easy way to start a new project using .Net Core WebAPI in server side and VueJs in the client side. For this goal, we setup the main configuration to enable this integration using some utilities as hot reloading and some frontend libraries as Element-UI and FontAwesome. 7 | 8 | Our goal is to provide a simple SPA with minimum dependencies and performance issues. The VueJs is configured with Vuex and Vue Router, but this can be removed if you don't feel it meets your requirement. The same goes for the component library. In this template, we also provide examples with the main functionalits. 9 | 10 | This template is inspired and adapted from [Mark Pieszak's project](https://github.com/MarkPieszak/aspnetcore-Vue-starter) and [Nordes' project](https://github.com/Nordes/HoNoSoFt.DotNet.Web.Spa.ProjectTemplates). 11 | 12 | # Table Of Contents 13 | - [Table Of Contents](#table-of-contents) 14 | - [Technology inside](#technology-inside) 15 | - [Installation](#installation) 16 | - [Update your installation?](#update-your-installation) 17 | - [Uninstallation](#uninstallation) 18 | - [Develop](#develop) 19 | - [Publishing your application](#publishing-your-application) 20 | - [Before publishing](#before-publishing) 21 | - [Publishing](#publishing) 22 | - [Extra if you use NginX](#extra-if-you-use-nginx) 23 | - [Docker](#docker) 24 | - [Docker - Build yourself](#docker---build-yourself) 25 | - [Some Automation](#some-automation) 26 | - [Kestrel serving using Gzip compression](#kestrel-serving-using-gzip-compression) 27 | - [Base components](#base-components) 28 | - [Webpack build](#webpack-build) 29 | - [Vuex](#vuex) 30 | - [Look'n feel](#lookn-feel) 31 | - [Element UI](#element-ui) 32 | 38 | - [License](#license) 39 | 40 | 41 | ## Technology inside 42 | 43 | - .Net Core 3.0 44 | - VueJs 45 | - Webpack 4 46 | - Element UI 47 | - Babel 48 | - Vuex 49 | - Vue-router 50 | - Eslint (airbnb + vuejs-recomended) 51 | - Swagger * 52 | - Vue-i18n * 53 | - Vee-validate * 54 | - LiveReload * 55 | 56 | \* Work In Progress. Available in future releases. 57 | 58 | ## Installation 59 | To download and install the template, just type: 60 | 61 | ```bash 62 | > dotnet new -i aspdotnet-vuejs 63 | ``` 64 | 65 | > You can see a list of installed templates by using the `dotnet new -l` command. 66 | 67 | Then to create your project you will simply use the command bellow in the directory: 68 | 69 | ```bash 70 | > dotnet new vue 71 | ``` 72 | 73 | This will automatically run `dotnet restore`. But it can be changed in template configurations. 74 | See `dotnet new vue -h` before using the previous command. 75 | 76 | > The solution and project name will be the name of the directory. 77 | 78 | ### Update your installation 79 | To update your installation, you will just need to repeat the installation process. 80 | As long as the version number are not equals, you won't have any unexpected behaviour. 81 | 82 | ### Uninstallation 83 | 84 | Type the following command from the shell: 85 | 86 | ```bash 87 | > dotnet new -u aspdotnet-vuejs 88 | ``` 89 | 90 | ## Develop 91 | 92 | To start developing your application, just use the .Net CLI command: 93 | 94 | ```bash 95 | > dotnet run YourAplication.csproj 96 | ``` 97 | 98 | > You can just type `dotnet run` in the project directory or configure your IDE to run. 99 | > In this last case just don't forget to pass the `ASPNETCORE_ENVIRONMENT=Development` environment variable. 100 | 101 | This will also run all node dependencies like `npm i`. 102 | 103 | > The application will be started in _Development_ mode with hot reloading 104 | > enabled at `https://localhost:5001` and `http://localhost:5000`. 105 | 106 | ## Publishing your application 107 | ### Before publishing 108 | You need to ensure that your wwwroot **is empty** before starting the process. 109 | 110 | ### Publishing 111 | Simply use the normal way of publishing using .Net Core CLI 112 | 113 | ```bash 114 | > dotnet publish YourProject.csproj -c release -o ./publish/ 115 | ``` 116 | 117 | > You can also add all the other parameter from the dotnet cli. 118 | > Please [visit the MSDN site](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21) to know more about it. 119 | 120 | This will do a rebuild of your project and then after it will use the special target to rebuild your client (vuejs) in production mode. 121 | 122 | ### Extra if you use NginX 123 | If you are publishing behind a NginX server, you might need more configuration. 124 | 125 | Let's say you have your base site `http://www.example.com` and that in your NginX configuration you would like to have your dotnet app within `http://www.example.com/myApp`. You will need in such a scenario to set the base uri for the index.html. Instead of doing that manually between development and production, you have the file `./build/base.prod.config.js` which contains a possible override. 126 | 127 | Simply set your override like the following: 128 | 129 | ```javascript 130 | module.exports = { 131 | baseUriPath: '/myApp/' 132 | } 133 | ``` 134 | 135 | When you will publish next time, the path will then be taken into account and it will sets automatically the base uri path. 136 | 137 | ## Docker 138 | The project already add some [docker container](https://hub.docker.com/r/hvpaiva/aspdotnet-vuejs/) available through the Docker Hub. You can pull the image if you want. It will make the sample available locally. The image is using the Alpine version so it only uses a small footprint. 139 | 140 | ### Docker - Build yourself 141 | Since containers in docker are quite popular, a `Dockerfile` is also included within the template root folder. Don't forget the `.dockerignore` where some files are being ignored in order to avoid some unwanted file to be copied before publishing. 142 | 143 | > Ensure that you have Docker installed. 144 | 145 | ## Some Automation 146 | 147 | ### Kestrel serving using Gzip compression 148 | The code is having built-in the Gzip compression on the HTTPs. It's good to use that code especially if you use Kestrel. Otherwise, if you use IIS, please remove that specific code found in the `Startup.cs`. Normally, IIS offer it's own compression module which is more performant. 149 | 150 | ### Base components 151 | There's some automation regarding the `Components` available within _./ClientApp/components/**/*_. 152 | All the file starting with the keyword `base` are going to be declared as global and the name of the component to be used anywhere will be defined in _snake case_ without the `base` keyword. 153 | 154 | **Example:** `baseHelloWorld` will be registered as `hello-world` and you are going to be able to use it in your Vue Template. 155 | 156 | ```html 157 | 162 | ``` 163 | 164 | > There's a real example within the project for the card component for each page. The name of the component is `baseCard.vue`. 165 | 166 | ### Webpack build 167 | The css is not generated while you are in development mode. They are going to be created only when you will use the `dotnet publish` command or as an alternative, you can also go and type `npm run build -- --prod` which will launch the production build with the minification and extraction of the files. 168 | 169 | > **Important:** Currently, webpack clean the entire wwwroot folder within the .Net project. So, if you have static files, move them within the _./ClientApp/static/_ folder. 170 | 171 | ## Look'n feel 172 | 173 | ### Element UI 174 | To help make the development faster, we provide the installation of the component library [Element-UI](http://element.eleme.io/#/en-US). The documentation of this library can be founded in his site. 175 | 176 | > It can be removed normally in `main.js` if you don't need. 177 | 178 | 179 | 203 | 204 | ## License 205 | ![License MIT](https://img.shields.io/github/license/hvpaiva/aspdotnet-vuejs.svg) 206 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | version: 3.0.{build} 4 | 5 | install: 6 | # - ps: (new-object Net.WebClient).DownloadString("https://raw.github.com/madskristensen/ExtensionScripts/master/AppVeyor/vsix.ps1") | iex 7 | 8 | before_build: 9 | - ps: write-host Build v. $env:appveyor_build_version 10 | - nuget restore 11 | # - ps: Vsix-IncrementVsixVersion | Vsix-UpdateBuildVersion 12 | 13 | dotnet_csproj: 14 | patch: true 15 | file: '**\*.csproj' 16 | version: '{version}' 17 | package_version: '{version}' 18 | assembly_version: '{version}' 19 | file_version: '{version}' 20 | informational_version: '{version}' 21 | 22 | build_script: 23 | - msbuild /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /v:m 24 | - ps: (Get-Content AspDotnetVueJs.nuspec).replace('{{version}}', $env:appveyor_build_version ) | Set-Content AspDotnetVueJs.nuspec 25 | - nuget pack 26 | #Nuget auto-packaging can also be done cref: https://www.appveyor.com/docs/deployment/nuget/ 27 | 28 | after_build: 29 | - ps: Get-ChildItem .\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } 30 | - ps: Get-ChildItem .\*.nupkg | % { dotnet new -i $_.FullName } 31 | - ps: mkdir demo.dotnetvue 32 | - ps: cd demo.dotnetvue 33 | - ps: dotnet new vuejs 34 | - npm install 35 | - ps: dotnet publish demo.dotnetvue.csproj -c release -r win-x86 -o ./output --self-contained 36 | 37 | artifacts: 38 | - path: demo.dotnetvue\output 39 | name: dotnet-vuejs 40 | 41 | -------------------------------------------------------------------------------- /content/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "@babel/plugin-transform-runtime", 7 | "@babel/plugin-transform-async-to-generator", 8 | "@babel/plugin-syntax-dynamic-import", 9 | "@babel/plugin-syntax-import-meta", 10 | "@babel/plugin-proposal-class-properties", 11 | "@babel/plugin-proposal-json-strings", 12 | [ 13 | "@babel/plugin-proposal-decorators", 14 | { 15 | "legacy": true 16 | } 17 | ], 18 | "@babel/plugin-proposal-function-sent", 19 | "@babel/plugin-proposal-export-namespace-from", 20 | "@babel/plugin-proposal-numeric-separator", 21 | "@babel/plugin-proposal-throw-expressions" 22 | ], 23 | "comments": false 24 | } 25 | -------------------------------------------------------------------------------- /content/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | obj/ 3 | bin/ 4 | 5 | wwwroot/** 6 | 7 | # User-specific files 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | .dockerignore 14 | -------------------------------------------------------------------------------- /content/.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | trim_trailing_whitespace = false 5 | insert_final_newline = false 6 | indent_style = space 7 | indent_size = 4 8 | 9 | # Microsoft .NET properties 10 | csharp_new_line_before_members_in_object_initializers = false 11 | csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion 12 | csharp_style_var_elsewhere = true:hint 13 | csharp_style_var_for_built_in_types = true:hint 14 | csharp_style_var_when_type_is_apparent = true:hint 15 | dotnet_style_predefined_type_for_locals_parameters_members = true:hint 16 | dotnet_style_predefined_type_for_member_access = true:hint 17 | dotnet_style_qualification_for_event = false:warning 18 | dotnet_style_qualification_for_field = false:warning 19 | dotnet_style_qualification_for_method = false:warning 20 | dotnet_style_qualification_for_property = false:warning 21 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:hint 22 | 23 | # ReSharper properties 24 | resharper_autodetect_indent_settings = true 25 | resharper_use_indent_from_vs = false 26 | 27 | # ReSharper inspection severities 28 | resharper_bad_attribute_brackets_spaces_highlighting = warning 29 | resharper_bad_braces_spaces_highlighting = warning 30 | resharper_bad_colon_spaces_highlighting = warning 31 | resharper_bad_comma_spaces_highlighting = warning 32 | resharper_bad_control_braces_line_breaks_highlighting = warning 33 | resharper_bad_declaration_braces_indent_highlighting = warning 34 | resharper_bad_declaration_braces_line_breaks_highlighting = warning 35 | resharper_bad_empty_braces_line_breaks_highlighting = warning 36 | resharper_bad_expression_braces_indent_highlighting = warning 37 | resharper_bad_expression_braces_line_breaks_highlighting = warning 38 | resharper_bad_generic_brackets_spaces_highlighting = warning 39 | resharper_bad_indent_highlighting = warning 40 | resharper_bad_linq_line_breaks_highlighting = warning 41 | resharper_bad_list_line_breaks_highlighting = warning 42 | resharper_bad_member_access_spaces_highlighting = warning 43 | resharper_bad_namespace_braces_indent_highlighting = warning 44 | resharper_bad_parens_line_breaks_highlighting = warning 45 | resharper_bad_parens_spaces_highlighting = warning 46 | resharper_bad_preprocessor_indent_highlighting = warning 47 | resharper_bad_semicolon_spaces_highlighting = warning 48 | resharper_bad_spaces_after_keyword_highlighting = warning 49 | resharper_bad_square_brackets_spaces_highlighting = warning 50 | resharper_bad_switch_braces_indent_highlighting = warning 51 | resharper_bad_symbol_spaces_highlighting = warning 52 | resharper_class_never_instantiated_global_highlighting = none 53 | resharper_incorrect_blank_lines_near_braces_highlighting = warning 54 | resharper_missing_blank_lines_highlighting = warning 55 | resharper_missing_indent_highlighting = warning 56 | resharper_missing_linebreak_highlighting = warning 57 | resharper_missing_space_highlighting = warning 58 | resharper_multiple_spaces_highlighting = warning 59 | resharper_multiple_statements_on_one_line_highlighting = warning 60 | resharper_multiple_type_members_on_one_line_highlighting = warning 61 | resharper_outdent_is_off_prev_level_highlighting = warning 62 | resharper_redundant_blank_lines_highlighting = warning 63 | resharper_redundant_linebreak_highlighting = warning 64 | resharper_redundant_space_highlighting = warning 65 | resharper_tabs_and_spaces_mismatch_highlighting = warning 66 | resharper_tabs_outside_indent_highlighting = warning 67 | resharper_unused_member_global_highlighting = none 68 | resharper_unused_parameter_global_highlighting = none 69 | resharper_web_config_module_not_resolved_highlighting = warning 70 | resharper_web_config_type_not_resolved_highlighting = warning 71 | resharper_web_config_wrong_module_highlighting = warning 72 | resharper_wrong_indent_size_highlighting = warning 73 | 74 | [{*.sht, *.html, *.shtm, *.shtml, *.ng, *.htm}] 75 | indent_style = tab 76 | tab_width = 4 77 | 78 | [*.svg] 79 | indent_style = tab 80 | tab_width = 4 81 | 82 | [{.babelrc, .stylelintrc, jest.config, *.uplugin, *.uproject, *.bowerrc, *.jsb3, *.jsb2, *.json}] 83 | indent_style = tab 84 | tab_width = 4 85 | 86 | [{*.targets, *.overridetasks, *.tasks}] 87 | indent_style = tab 88 | tab_width = 4 89 | 90 | [{*.csproj, *.ccproj, *.androidproj}] 91 | indent_style = tab 92 | tab_width = 4 93 | 94 | [{*.vcxitems, *.vcxproj}] 95 | indent_style = tab 96 | tab_width = 4 97 | 98 | [*.css] 99 | indent_style = tab 100 | tab_width = 4 101 | 102 | [*.less] 103 | indent_style = space 104 | indent_size = 2 105 | 106 | [*.sass] 107 | indent_style = tab 108 | tab_width = 4 109 | 110 | [*.scss] 111 | indent_style = tab 112 | tab_width = 4 113 | 114 | [{*.cjs, *.js}] 115 | indent_style = tab 116 | tab_width = 4 117 | 118 | [{*.ats, *.ts}] 119 | indent_style = tab 120 | tab_width = 4 121 | 122 | [{tsconfig.lib.json, tsconfig.spec.json, tsconfig.app.json, tsconfig.json, tsconfig.e2e.json}] 123 | indent_style = tab 124 | tab_width = 4 125 | 126 | [*.js.map] 127 | indent_style = tab 128 | tab_width = 4 129 | 130 | [{*.pug, *.jade}] 131 | indent_style = tab 132 | tab_width = 4 133 | 134 | [*.vue] 135 | indent_style = tab 136 | tab_width = 4 137 | 138 | [{*.yml, *.yaml}] 139 | indent_style = space 140 | indent_size = 2 141 | 142 | [.eslintrc] 143 | indent_style = tab 144 | tab_width = 4 145 | 146 | [*.{appxmanifest, asax, ascx, aspx, build, config, cs, cshtml, csproj, dbml, discomap, dtd, fs, fsi, fsscript, fsx, htm, html, jsproj, lsproj, master, ml, mli, njsproj, nuspec, proj, props, razor, resw, resx, skin, StyleCop, targets, tasks, vb, vbproj, xaml, xamlx, xml, xoml, xsd}] 147 | indent_style = space 148 | indent_size = 4 149 | tab_width = 4 150 | -------------------------------------------------------------------------------- /content/.eslintignore: -------------------------------------------------------------------------------- 1 | ###################################################### 2 | # https://eslint.org/docs/user-guide/configuring 3 | ###################################################### 4 | # /node_modules/* and /bower_components/* in the project root are ignored by default 5 | # Ignore built files except build/index.js 6 | /ClientApp/static/**/*.js 7 | 8 | # !build/index.js ... if i would like to ignore all except that... then it's the way 9 | -------------------------------------------------------------------------------- /content/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: "babel-eslint", 5 | sourceType: "module" 6 | }, 7 | "extends": [ 8 | "airbnb", 9 | "plugin:vue/recommended" 10 | ], 11 | plugins: [ 12 | 'vue' 13 | ], 14 | 'rules': { 15 | 'arrow-parens': 0, 16 | 'generator-star-spacing': 0, 17 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 18 | 'no-console': process.env.NODE_ENV === 'production' ? 2 : 0, 19 | 'comma-dangle': ['error', 'never'], 20 | 'no-shadow': 0, 21 | 'no-param-reassign': ["error", { "props": true, "ignorePropertyModificationsFor": ["state"] }], 22 | 'object-curly-newline': ["error", { "consistent": true }], 23 | 'unicode-bom': 0, 24 | 'import/no-unresolved': 0, 25 | 'vue/script-indent': ['error', "tab", { 'baseIndent': 0 , "switchCase": 1}], 26 | 'vue/html-indent': ['error', "tab", { 'baseIndent': 1 }], 27 | 'no-tabs': 0, 28 | "indent": ["error", "tab", { "SwitchCase": 1 }], 29 | "no-mixed-operators": 0, 30 | "import/prefer-default-export": 0, 31 | "no-use-before-define": 0, 32 | "no-plusplus": 0, 33 | "no-mixed-spaces-and-tabs": ["error", "smart-tabs"], 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /content/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log 4 | 5 | # /Properties/launchSettings.json 6 | 7 | package-lock.json 8 | 9 | ## Ignore Visual Studio temporary files, build results, and 10 | ## files generated by popular Visual Studio add-ons. 11 | 12 | # User-specific files 13 | *.suo 14 | *.user 15 | *.userosscache 16 | *.sln.docstates 17 | 18 | # User-specific files (MonoDevelop/Xamarin Studio) 19 | *.userprefs 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | bld/ 29 | bin/ 30 | Bin/ 31 | obj/ 32 | Obj/ 33 | 34 | # Visual Studio 2015 cache/options directory 35 | .vs/ 36 | /wwwroot/dist/** 37 | 38 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235 39 | !/wwwroot/dist/_placeholder.txt 40 | 41 | /yarn.lock 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUNIT 48 | *.VisualState.xml 49 | TestResult.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # DNX 57 | project.lock.json 58 | artifacts/ 59 | 60 | *_i.c 61 | *_p.c 62 | *_i.h 63 | *.ilk 64 | *.meta 65 | *.obj 66 | *.pch 67 | *.pdb 68 | *.pgc 69 | *.pgd 70 | *.rsp 71 | *.sbr 72 | *.tlb 73 | *.tli 74 | *.tlh 75 | *.tmp 76 | *.tmp_proj 77 | *.log 78 | *.vspscc 79 | *.vssscc 80 | .builds 81 | *.pidb 82 | *.svclog 83 | *.scc 84 | 85 | # Chutzpah Test files 86 | _Chutzpah* 87 | 88 | # Visual C++ cache files 89 | ipch/ 90 | *.aps 91 | *.ncb 92 | *.opendb 93 | *.opensdf 94 | *.sdf 95 | *.cachefile 96 | 97 | # Visual Studio profiler 98 | *.psess 99 | *.vsp 100 | *.vspx 101 | *.sap 102 | 103 | # TFS 2012 Local Workspace 104 | $tf/ 105 | 106 | # Guidance Automation Toolkit 107 | *.gpState 108 | 109 | # ReSharper is a .NET coding add-in 110 | _ReSharper*/ 111 | *.[Rr]e[Ss]harper 112 | *.DotSettings.user 113 | 114 | # JustCode is a .NET coding add-in 115 | .JustCode 116 | 117 | # TeamCity is a build add-in 118 | _TeamCity* 119 | 120 | # DotCover is a Code Coverage Tool 121 | *.dotCover 122 | 123 | # NCrunch 124 | _NCrunch_* 125 | .*crunch*.local.xml 126 | nCrunchTemp_* 127 | 128 | # MightyMoose 129 | *.mm.* 130 | AutoTest.Net/ 131 | 132 | # Web workbench (sass) 133 | .sass-cache/ 134 | 135 | # Installshield output folder 136 | [Ee]xpress/ 137 | 138 | # DocProject is a documentation generator add-in 139 | DocProject/buildhelp/ 140 | DocProject/Help/*.HxT 141 | DocProject/Help/*.HxC 142 | DocProject/Help/*.hhc 143 | DocProject/Help/*.hhk 144 | DocProject/Help/*.hhp 145 | DocProject/Help/Html2 146 | DocProject/Help/html 147 | 148 | # Click-Once directory 149 | publish/ 150 | 151 | # Publish Web Output 152 | *.[Pp]ublish.xml 153 | *.azurePubxml 154 | # TODO: Comment the next line if you want to checkin your web deploy settings 155 | # but database connection strings (with potential passwords) will be unencrypted 156 | *.pubxml 157 | *.publishproj 158 | 159 | # NuGet Packages 160 | *.nupkg 161 | # The packages folder can be ignored because of Package Restore 162 | **/packages/* 163 | # except build/, which is used as an MSBuild target. 164 | !**/packages/build/ 165 | # Uncomment if necessary however generally it will be regenerated when needed 166 | #!**/packages/repositories.config 167 | 168 | # Microsoft Azure Build Output 169 | csx/ 170 | *.build.csdef 171 | 172 | # Microsoft Azure Emulator 173 | ecf/ 174 | rcf/ 175 | 176 | # Microsoft Azure ApplicationInsights config file 177 | ApplicationInsights.config 178 | 179 | # Windows Store app package directory 180 | AppPackages/ 181 | BundleArtifacts/ 182 | 183 | # Visual Studio cache files 184 | # files ending in .cache can be ignored 185 | *.[Cc]ache 186 | # but keep track of directories ending in .cache 187 | !*.[Cc]ache/ 188 | 189 | # Others 190 | ClientBin/ 191 | ~$* 192 | *~ 193 | *.dbmdl 194 | *.dbproj.schemaview 195 | *.pfx 196 | *.publishsettings 197 | orleans.codegen.cs 198 | 199 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235 200 | /node_modules/** 201 | !/node_modules/_placeholder.txt 202 | 203 | # RIA/Silverlight projects 204 | Generated_Code/ 205 | 206 | # Backup & report files from converting an old project file 207 | # to a newer Visual Studio version. Backup files are not needed, 208 | # because we have git ;-) 209 | _UpgradeReport_Files/ 210 | Backup*/ 211 | UpgradeLog*.XML 212 | UpgradeLog*.htm 213 | 214 | # SQL Server files 215 | *.mdf 216 | *.ldf 217 | 218 | # Business Intelligence projects 219 | *.rdl.data 220 | *.bim.layout 221 | *.bim_*.settings 222 | 223 | # Microsoft Fakes 224 | FakesAssemblies/ 225 | 226 | # GhostDoc plugin setting file 227 | *.GhostDoc.xml 228 | 229 | # Node.js Tools for Visual Studio 230 | .ntvs_analysis.dat 231 | 232 | # Visual Studio 6 build log 233 | *.plg 234 | 235 | # Visual Studio 6 workspace options file 236 | *.opt 237 | 238 | # Visual Studio LightSwitch build output 239 | **/*.HTMLClient/GeneratedArtifacts 240 | **/*.DesktopClient/GeneratedArtifacts 241 | **/*.DesktopClient/ModelManifest.xml 242 | **/*.Server/GeneratedArtifacts 243 | **/*.Server/ModelManifest.xml 244 | _Pvt_Extensions 245 | 246 | # Paket dependency manager 247 | .paket/paket.exe 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | .vscode/ 253 | -------------------------------------------------------------------------------- /content/.template.config/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/template", 3 | "author": "Highlander Paiva", 4 | "classifications": [ "Web", "WebAPI", "SPA" ], 5 | "groupIdentity": "AspDotnetVueJs", 6 | "identity": "AspDotnetVueJs", 7 | "name": "ASP.NET Core with VueJs", 8 | "preferNameDirectory": true, 9 | "primaryOutputs": [ 10 | { 11 | "path": "AspDotnetVueJs.csproj" 12 | } 13 | ], 14 | "shortName": "vue", 15 | "sourceName": "AspDotnetVueJs", 16 | "sources": [ 17 | { 18 | "source": "./", 19 | "target": "./", 20 | "exclude": [ 21 | ".template.config/**" 22 | ], 23 | "modifiers": [ 24 | { 25 | "condition": "(TargetFrameworkOverride == '')", 26 | "exclude": [ 27 | "app.config" 28 | ] 29 | }, 30 | { 31 | "condition": "(ExcludeLaunchSettings)", 32 | "exclude": [ 33 | "Properties/launchSettings.json" 34 | ] 35 | } 36 | ] 37 | } 38 | ], 39 | "symbols": { 40 | "ExcludeLaunchSettings": { 41 | "type": "parameter", 42 | "datatype": "bool", 43 | "defaultValue": "false", 44 | "description": "Whether to exclude launchSettings.json from the generated template." 45 | }, 46 | "HttpPort": { 47 | "type": "parameter", 48 | "datatype": "integer", 49 | "description": "Port number to use for the HTTP endpoint in launchSettings.json." 50 | }, 51 | "HttpPortGenerated": { 52 | "type": "generated", 53 | "generator": "port" 54 | }, 55 | "HttpPortReplacer": { 56 | "type": "generated", 57 | "generator": "coalesce", 58 | "parameters": { 59 | "sourceVariableName": "HttpPort", 60 | "fallbackVariableName": "HttpPortGenerated" 61 | }, 62 | "replaces": "8080" 63 | }, 64 | "HttpsPort": { 65 | "type": "parameter", 66 | "datatype": "integer", 67 | "description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used)." 68 | }, 69 | "HttpsPortGenerated": { 70 | "type": "generated", 71 | "generator": "port", 72 | "parameters": { 73 | "low": 44300, 74 | "high": 44399 75 | } 76 | }, 77 | "HttpsPortReplacer": { 78 | "type": "generated", 79 | "generator": "coalesce", 80 | "parameters": { 81 | "sourceVariableName": "HttpsPort", 82 | "fallbackVariableName": "HttpsPortGenerated" 83 | }, 84 | "replaces": "44300" 85 | }, 86 | "TargetFrameworkOverride": { 87 | "type": "parameter", 88 | "description": "Overrides the target framework", 89 | "replaces": "TargetFrameworkOverride", 90 | "datatype": "string", 91 | "defaultValue": "" 92 | }, 93 | "Framework": { 94 | "type": "parameter", 95 | "description": "The target framework for the project.", 96 | "datatype": "choice", 97 | "choices": [ 98 | { 99 | "choice": "netcoreapp2.2", 100 | "description": "Target netcoreapp2.2" 101 | } 102 | ], 103 | "replaces": "netcoreapp2.2", 104 | "defaultValue": "netcoreapp2.2" 105 | }, 106 | "HostIdentifier": { 107 | "type": "bind", 108 | "binding": "HostIdentifier" 109 | }, 110 | "skipRestore": { 111 | "type": "parameter", 112 | "datatype": "bool", 113 | "description": "If specified, skips the automatic restore of the project on create.", 114 | "defaultValue": "false" 115 | }, 116 | "NoHttps": { 117 | "type": "parameter", 118 | "datatype": "bool", 119 | "defaultValue": "false", 120 | "description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth." 121 | } 122 | }, 123 | "tags": { 124 | "language": "C#", 125 | "type": "project" 126 | }, 127 | 128 | 129 | "precedence": 100, 130 | "guids": [ 131 | "6B3E8EE8-92E3-41CE-A356-A5F880EEA367" 132 | ], 133 | "postActions": [ 134 | { 135 | "condition": "(!skipRestore)", 136 | "description": "Restore NuGet packages required by this project.", 137 | "manualInstructions": [ 138 | { 139 | "text": "Run 'dotnet restore'" 140 | } 141 | ], 142 | "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025", 143 | "continueOnError": true 144 | } 145 | ] 146 | } 147 | -------------------------------------------------------------------------------- /content/AspDotnetVueJs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | true 6 | $(DefaultItemExcludes);$(SpaRoot)node_modules\** 7 | 8 | 9 | false 10 | AspDotnetVueJs 11 | 12 | 13 | 14 | true 15 | $(NoWarn);1591 16 | 17 | 18 | 19 | obj\Debug\netcoreapp3.0\AspDotnetVueJs.xml 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | <_ContentIncludedByDefault Remove="wwwroot\dist\0.js" /> 42 | <_ContentIncludedByDefault Remove="wwwroot\dist\0.js.map" /> 43 | <_ContentIncludedByDefault Remove="wwwroot\dist\1.js" /> 44 | <_ContentIncludedByDefault Remove="wwwroot\dist\1.js.map" /> 45 | <_ContentIncludedByDefault Remove="wwwroot\dist\fonts\element-icons.2fad952a.woff" /> 46 | <_ContentIncludedByDefault Remove="wwwroot\dist\fonts\element-icons.6f0a7632.ttf" /> 47 | <_ContentIncludedByDefault Remove="wwwroot\dist\main.js" /> 48 | <_ContentIncludedByDefault Remove="wwwroot\dist\main.js.map" /> 49 | <_ContentIncludedByDefault Remove="wwwroot\dist\vendor.js" /> 50 | <_ContentIncludedByDefault Remove="wwwroot\dist\vendor.js.map" /> 51 | <_ContentIncludedByDefault Remove="wwwroot\favicon.ico" /> 52 | <_ContentIncludedByDefault Remove="wwwroot\index.html" /> 53 | <_ContentIncludedByDefault Remove="wwwroot\static\ie-polyfill.min.js" /> 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | %(DistFiles.Identity) 83 | PreserveNewest 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /content/ClientApp/app.js: -------------------------------------------------------------------------------- 1 | // Core imports 2 | import Vue from 'vue'; 3 | import upperFirst from 'lodash/upperFirst'; 4 | import camelCase from 'lodash/camelCase'; 5 | import router from './router/index'; 6 | import store from './store'; 7 | import App from './components/App'; 8 | import { FontAwesomeIcon } from './icons'; 9 | 10 | // 3th imports 11 | import { sync } from 'vuex-router-sync'; 12 | import axios from 'axios'; 13 | import ElementUI from 'element-ui'; 14 | import locale from 'element-ui/lib/locale/lang/en'; 15 | 16 | // CSS imports 17 | import './styles/main.sass'; 18 | 19 | // Configurations 20 | Vue.use(ElementUI, { locale }); 21 | Vue.component('icon', FontAwesomeIcon); 22 | Vue.prototype.$http = axios; 23 | sync(store, router); 24 | 25 | // Mode details on: https://vuejs.org/v2/guide/components-registration.html 26 | const requireComponent = require.context( 27 | // The relative path of the components folder 28 | './components', 29 | // Whether or not to look in subfolders 30 | true, 31 | // The regular expression used to match base component filenames 32 | /base[A-Z]\w+\.(vue|js)$/ 33 | ); 34 | 35 | requireComponent.keys().forEach(fileName => { 36 | // Get component config 37 | const componentConfig = requireComponent(fileName); 38 | 39 | // Get PascalCase name of component 40 | const componentName = upperFirst( 41 | camelCase( 42 | // Strip the leading `./` and extension from the filename 43 | fileName.replace(/base/, '').replace(/^\.\/(.*)\.\w+$/, '$1') 44 | ) 45 | ); 46 | 47 | // Register component globally 48 | Vue.component( 49 | componentName, 50 | // Look for the component options on `.default`, which will 51 | // exist if the component was exported with `export default`, 52 | // otherwise fall back to module's root. 53 | componentConfig.default || componentConfig 54 | ); 55 | }); 56 | 57 | new Vue({ // eslint-disable-line 58 | el: '#app', 59 | store, 60 | router, 61 | ...App 62 | }); 63 | -------------------------------------------------------------------------------- /content/ClientApp/build/base.config.js: -------------------------------------------------------------------------------- 1 | const productionConfig = require('../../appsettings.json'); 2 | const devConfig = require('../../appsettings.Development.json'); 3 | 4 | const environment = process.env.NODE_ENV; 5 | const isProduction = environment === 'production'; 6 | 7 | const CurrentEnvironment = isProduction 8 | ? productionConfig 9 | : devConfig; 10 | 11 | const has = Object.prototype.hasOwnProperty; 12 | 13 | module.exports = { 14 | 15 | environment, 16 | 17 | isProduction, 18 | 19 | baseUriPath: has.call(CurrentEnvironment, 'BaseUriPath') 20 | && CurrentEnvironment.BaseUriPath !== '' 21 | ? CurrentEnvironment.BaseUriPath 22 | : '/', 23 | 24 | generateMapFiles: has.call(CurrentEnvironment, 'GenerateMapFiles') 25 | ? CurrentEnvironment.GenerateMapFiles 26 | : false 27 | }; 28 | -------------------------------------------------------------------------------- /content/ClientApp/build/publishingLoader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Webpack - Building in progress... 4 | 75 | 76 | 77 |
78 |
79 |
80 | Building Frontend... 81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /content/ClientApp/build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const webpack = require('webpack'); 4 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 5 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 7 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 8 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 9 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 10 | const rimraf = require('rimraf'); 11 | const BaseConfig = require('./base.config'); 12 | const AppConfig = require('../../appsettings'); 13 | const LaunchConfig = require('../../Properties/launchSettings'); 14 | 15 | const rootDir = path.resolve(__dirname, '../..'); 16 | 17 | const bundleOutputDir = path.resolve(rootDir, './wwwroot/dist'); 18 | 19 | console.info(`Building for production: ${BaseConfig.isProduction}`); 20 | rimraf.sync(path.resolve(rootDir, 'wwwroot/**/*'), { silent: true }); 21 | 22 | if (!BaseConfig.isProduction) { 23 | fs.createReadStream(path.resolve(rootDir, 'ClientApp/build/publishingLoader.html')) 24 | .pipe(fs.createWriteStream(path.resolve(rootDir, 'wwwroot/index.html'))); 25 | } 26 | 27 | console.info(BaseConfig); 28 | 29 | module.exports = { 30 | name: 'app', 31 | devServer: { 32 | proxy: { 33 | '^/api': { 34 | target: LaunchConfig.profiles.AspDotnetVueJS.applicationUrl, 35 | ws: true, 36 | changeOrigin: true 37 | } 38 | } 39 | }, 40 | mode: BaseConfig.isProduction ? 'production' : 'development', 41 | stats: BaseConfig.isProduction ? 'errors-only' : 'normal', 42 | entry: { main: path.resolve(rootDir, './ClientApp/app.js') }, 43 | resolve: { 44 | extensions: ['.js', '.vue'], 45 | alias: { 46 | components: path.resolve(rootDir, './ClientApp/components') 47 | } 48 | }, 49 | optimization: { 50 | splitChunks: { 51 | cacheGroups: { 52 | commons: { 53 | chunks: 'initial', 54 | name: 'site', 55 | minChunks: 2, 56 | maxInitialRequests: 5, 57 | minSize: 0 58 | }, 59 | vendor: { 60 | test: /node_modules/, 61 | chunks: 'initial', 62 | name: 'vendor', 63 | priority: 10, 64 | enforce: true 65 | } 66 | } 67 | }, 68 | minimizer: [ 69 | new UglifyJsPlugin( 70 | { 71 | cache: true, 72 | parallel: true, 73 | sourceMap: !BaseConfig.isProduction 74 | } 75 | ), 76 | new OptimizeCSSAssetsPlugin({}) 77 | ], 78 | nodeEnv: BaseConfig.isProduction ? 'production' : 'development' 79 | }, 80 | output: { 81 | path: path.resolve(rootDir, './wwwroot/dist'), 82 | filename: !BaseConfig.isProduction ? '[name].js' : '[name].[hash].js', 83 | // publicPath: In production we don't use webpack hot reload, so it should be alright. 84 | // the usage of the at the beginning is for the basePath to be properly used. See 85 | // BaseConfig.baseUriPath. The webpack hot reload require the official URI path or you 86 | // will get errors in your console. 87 | publicPath: BaseConfig.isProduction ? `.${BaseConfig.baseUriPath}/dist/` : '/dist/' 88 | }, 89 | module: { 90 | rules: [ 91 | // this will apply to `.vue` 92 | { 93 | test: /\.vue$/, 94 | loader: 'vue-loader' 95 | }, 96 | // this will apply to both plain `.js` files 97 | // AND ` 28 | 29 | 48 | -------------------------------------------------------------------------------- /content/ClientApp/components/elements/CounterDisplay.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 51 | 52 | 89 | -------------------------------------------------------------------------------- /content/ClientApp/components/elements/DataTable.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 136 | 137 | 152 | -------------------------------------------------------------------------------- /content/ClientApp/components/layouts/CardContainer.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | 22 | 30 | -------------------------------------------------------------------------------- /content/ClientApp/components/layouts/HeaderLayout.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 46 | 47 | 61 | -------------------------------------------------------------------------------- /content/ClientApp/components/layouts/ViewLayout.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 17 | -------------------------------------------------------------------------------- /content/ClientApp/components/views/Counter.vue: -------------------------------------------------------------------------------- 1 |  28 | 29 | 73 | 74 | 80 | -------------------------------------------------------------------------------- /content/ClientApp/components/views/Home.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 89 | 90 | 92 | -------------------------------------------------------------------------------- /content/ClientApp/components/views/NotFound.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | 27 | 90 | -------------------------------------------------------------------------------- /content/ClientApp/components/views/WeatherForecast.vue: -------------------------------------------------------------------------------- 1 |  26 | 27 | 83 | 84 | 86 | -------------------------------------------------------------------------------- /content/ClientApp/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hvpaiva/aspdotnet-vuejs/e7bf3c5ed78e95f0f5a9a392b8dc32fdfdbe9b16/content/ClientApp/favicon.ico -------------------------------------------------------------------------------- /content/ClientApp/icons.js: -------------------------------------------------------------------------------- 1 | import { library } from '@fortawesome/fontawesome-svg-core'; 2 | // Official documentation available at: https://github.com/FortAwesome/vue-fontawesome 3 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; 4 | 5 | // If not present, it won't be visible within the application. Considering that you 6 | // don't want all the icons for no reason. This is a good way to avoid importing too many 7 | // unnecessary things. 8 | library.add( 9 | require('@fortawesome/free-solid-svg-icons').faGraduationCap, 10 | require('@fortawesome/free-solid-svg-icons').faList, 11 | require('@fortawesome/free-solid-svg-icons').faSpinner, 12 | require('@fortawesome/free-solid-svg-icons').faHome, 13 | // Brands 14 | require('@fortawesome/free-brands-svg-icons').faMicrosoft, 15 | require('@fortawesome/free-brands-svg-icons').faVuejs, 16 | require('@fortawesome/free-brands-svg-icons').faFontAwesome 17 | ); 18 | 19 | export { 20 | FontAwesomeIcon 21 | } 22 | -------------------------------------------------------------------------------- /content/ClientApp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <%= appName %> 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /content/ClientApp/models/WeatherForecast.js: -------------------------------------------------------------------------------- 1 | const WeatherForecast = { 2 | dateFormatted: null, 3 | temperatureC: null, 4 | temperatureF: null, 5 | summary: null 6 | }; 7 | 8 | export default WeatherForecast; 9 | -------------------------------------------------------------------------------- /content/ClientApp/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import routes from './routes'; 4 | 5 | Vue.use(VueRouter); 6 | 7 | const router = new VueRouter({ 8 | mode: 'history', 9 | routes 10 | }); 11 | 12 | export default router; 13 | -------------------------------------------------------------------------------- /content/ClientApp/router/routes.js: -------------------------------------------------------------------------------- 1 | import Home from '../components/views/Home'; 2 | import NotFound from '../components/views/NotFound'; 3 | 4 | const routes = [ 5 | { 6 | name: 'home', 7 | path: '/', 8 | component: Home, 9 | display: 'Home', 10 | icon: 'home' 11 | }, 12 | { 13 | name: 'counter', 14 | path: '/counter', 15 | component: () => import('../components/views/Counter'), 16 | display: 'Counter', 17 | icon: 'graduation-cap' 18 | }, 19 | { 20 | name: 'weather', 21 | path: '/weather', 22 | component: () => import('../components/views/WeatherForecast'), 23 | display: 'Weather forecast', 24 | icon: 'list' 25 | }, 26 | { name: '404', path: '/404', component: NotFound }, 27 | { name: 'catchAll', path: '*', redirect: '/404' } 28 | ]; 29 | 30 | export default routes; 31 | -------------------------------------------------------------------------------- /content/ClientApp/services/forecast-service.js: -------------------------------------------------------------------------------- 1 | import Axios from 'axios'; 2 | 3 | const ForecastService = { 4 | 5 | fetch: async (to, from) => Axios.get( 6 | `/api/weather/forecasts?from=${from}&to=${to}` 7 | ) 8 | }; 9 | 10 | export default ForecastService; 11 | -------------------------------------------------------------------------------- /content/ClientApp/static/ie-polyfill.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * @overview es6-promise - a tiny implementation of Promises/A+. 3 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) 4 | * @license Licensed under MIT license 5 | * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE 6 | * @version 3.2.1 7 | */ 8 | 9 | (function(){"use strict";function t(t){return"function"==typeof t||"object"==typeof t&&null!==t}function e(t){return"function"==typeof t}function n(t){G=t}function r(t){Q=t}function o(){return function(){process.nextTick(a)}}function i(){return function(){B(a)}}function s(){var t=0,e=new X(a),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function u(){var t=new MessageChannel;return t.port1.onmessage=a,function(){t.port2.postMessage(0)}}function c(){return function(){setTimeout(a,1)}}function a(){for(var t=0;J>t;t+=2){var e=tt[t],n=tt[t+1];e(n),tt[t]=void 0,tt[t+1]=void 0}J=0}function f(){try{var t=require,e=t("vertx");return B=e.runOnLoop||e.runOnContext,i()}catch(n){return c()}}function l(t,e){var n=this,r=new this.constructor(p);void 0===r[rt]&&k(r);var o=n._state;if(o){var i=arguments[o-1];Q(function(){x(o,r,i,n._result)})}else E(n,r,t,e);return r}function h(t){var e=this;if(t&&"object"==typeof t&&t.constructor===e)return t;var n=new e(p);return g(n,t),n}function p(){}function _(){return new TypeError("You cannot resolve a promise with itself")}function d(){return new TypeError("A promises callback cannot return that same promise.")}function v(t){try{return t.then}catch(e){return ut.error=e,ut}}function y(t,e,n,r){try{t.call(e,n,r)}catch(o){return o}}function m(t,e,n){Q(function(t){var r=!1,o=y(n,e,function(n){r||(r=!0,e!==n?g(t,n):S(t,n))},function(e){r||(r=!0,j(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&o&&(r=!0,j(t,o))},t)}function b(t,e){e._state===it?S(t,e._result):e._state===st?j(t,e._result):E(e,void 0,function(e){g(t,e)},function(e){j(t,e)})}function w(t,n,r){n.constructor===t.constructor&&r===et&&constructor.resolve===nt?b(t,n):r===ut?j(t,ut.error):void 0===r?S(t,n):e(r)?m(t,n,r):S(t,n)}function g(e,n){e===n?j(e,_()):t(n)?w(e,n,v(n)):S(e,n)}function A(t){t._onerror&&t._onerror(t._result),T(t)}function S(t,e){t._state===ot&&(t._result=e,t._state=it,0!==t._subscribers.length&&Q(T,t))}function j(t,e){t._state===ot&&(t._state=st,t._result=e,Q(A,t))}function E(t,e,n,r){var o=t._subscribers,i=o.length;t._onerror=null,o[i]=e,o[i+it]=n,o[i+st]=r,0===i&&t._state&&Q(T,t)}function T(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,o,i=t._result,s=0;si;i++)e.resolve(t[i]).then(n,r)}:function(t,e){e(new TypeError("You must pass an array to race."))})}function F(t){var e=this,n=new e(p);return j(n,t),n}function D(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function K(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function L(t){this[rt]=O(),this._result=this._state=void 0,this._subscribers=[],p!==t&&("function"!=typeof t&&D(),this instanceof L?C(this,t):K())}function N(t,e){this._instanceConstructor=t,this.promise=new t(p),this.promise[rt]||k(this.promise),I(e)?(this._input=e,this.length=e.length,this._remaining=e.length,this._result=new Array(this.length),0===this.length?S(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&S(this.promise,this._result))):j(this.promise,U())}function U(){return new Error("Array Methods must be provided an Array")}function W(){var t;if("undefined"!=typeof global)t=global;else if("undefined"!=typeof self)t=self;else try{t=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=t.Promise;(!n||"[object Promise]"!==Object.prototype.toString.call(n.resolve())||n.cast)&&(t.Promise=pt)}var z;z=Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};var B,G,H,I=z,J=0,Q=function(t,e){tt[J]=t,tt[J+1]=e,J+=2,2===J&&(G?G(a):H())},R="undefined"!=typeof window?window:void 0,V=R||{},X=V.MutationObserver||V.WebKitMutationObserver,Z="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),$="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,tt=new Array(1e3);H=Z?o():X?s():$?u():void 0===R&&"function"==typeof require?f():c();var et=l,nt=h,rt=Math.random().toString(36).substring(16),ot=void 0,it=1,st=2,ut=new M,ct=new M,at=0,ft=Y,lt=q,ht=F,pt=L;L.all=ft,L.race=lt,L.resolve=nt,L.reject=ht,L._setScheduler=n,L._setAsap=r,L._asap=Q,L.prototype={constructor:L,then:et,"catch":function(t){return this.then(null,t)}};var _t=N;N.prototype._enumerate=function(){for(var t=this.length,e=this._input,n=0;this._state===ot&&t>n;n++)this._eachEntry(e[n],n)},N.prototype._eachEntry=function(t,e){var n=this._instanceConstructor,r=n.resolve;if(r===nt){var o=v(t);if(o===et&&t._state!==ot)this._settledAt(t._state,e,t._result);else if("function"!=typeof o)this._remaining--,this._result[e]=t;else if(n===pt){var i=new n(p);w(i,t,o),this._willSettleAt(i,e)}else this._willSettleAt(new n(function(e){e(t)}),e)}else this._willSettleAt(r(t),e)},N.prototype._settledAt=function(t,e,n){var r=this.promise;r._state===ot&&(this._remaining--,t===st?j(r,n):this._result[e]=n),0===this._remaining&&S(r,this._result)},N.prototype._willSettleAt=function(t,e){var n=this;E(t,void 0,function(t){n._settledAt(it,e,t)},function(t){n._settledAt(st,e,t)})};var dt=W,vt={Promise:pt,polyfill:dt};"function"==typeof define&&define.amd?define(function(){return vt}):"undefined"!=typeof module&&module.exports?module.exports=vt:"undefined"!=typeof this&&(this.ES6Promise=vt),dt()}).call(this); 10 | 11 | /*! 12 | * @overview fetch - The fetch() function is a Promise-based mechanism for programmatically making web requests in the browser. 13 | * @license Licensed under MIT license 14 | * See https://raw.githubusercontent.com/github/fetch/master/LICENSE 15 | * @version 3.0.0 16 | */ 17 | var support={searchParams:"URLSearchParams"in self,iterable:"Symbol"in self&&"iterator"in Symbol,blob:"FileReader"in self&&"Blob"in self&&function(){try{return new Blob,!0}catch(e){return!1}}(),formData:"FormData"in self,arrayBuffer:"ArrayBuffer"in self};function isDataView(e){return e&&DataView.prototype.isPrototypeOf(e)}if(support.arrayBuffer)var viewClasses=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],isArrayBufferView=ArrayBuffer.isView||function(e){return e&&viewClasses.indexOf(Object.prototype.toString.call(e))>-1};function normalizeName(e){if("string"!=typeof e&&(e=String(e)),/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(e))throw new TypeError("Invalid character in header field name");return e.toLowerCase()}function normalizeValue(e){return"string"!=typeof e&&(e=String(e)),e}function iteratorFor(e){var t={next:function(){var t=e.shift();return{done:void 0===t,value:t}}};return support.iterable&&(t[Symbol.iterator]=function(){return t}),t}function Headers(e){this.map={},e instanceof Headers?e.forEach(function(e,t){this.append(t,e)},this):Array.isArray(e)?e.forEach(function(e){this.append(e[0],e[1])},this):e&&Object.getOwnPropertyNames(e).forEach(function(t){this.append(t,e[t])},this)}function consumed(e){if(e.bodyUsed)return Promise.reject(new TypeError("Already read"));e.bodyUsed=!0}function fileReaderReady(e){return new Promise(function(t,r){e.onload=function(){t(e.result)},e.onerror=function(){r(e.error)}})}function readBlobAsArrayBuffer(e){var t=new FileReader,r=fileReaderReady(t);return t.readAsArrayBuffer(e),r}function readBlobAsText(e){var t=new FileReader,r=fileReaderReady(t);return t.readAsText(e),r}function readArrayBufferAsText(e){for(var t=new Uint8Array(e),r=new Array(t.length),o=0;o-1?t:e}function Request(e,t){var r=(t=t||{}).body;if(e instanceof Request){if(e.bodyUsed)throw new TypeError("Already read");this.url=e.url,this.credentials=e.credentials,t.headers||(this.headers=new Headers(e.headers)),this.method=e.method,this.mode=e.mode,this.signal=e.signal,r||null==e._bodyInit||(r=e._bodyInit,e.bodyUsed=!0)}else this.url=String(e);if(this.credentials=t.credentials||this.credentials||"same-origin",!t.headers&&this.headers||(this.headers=new Headers(t.headers)),this.method=normalizeMethod(t.method||this.method||"GET"),this.mode=t.mode||this.mode||null,this.signal=t.signal||this.signal,this.referrer=null,("GET"===this.method||"HEAD"===this.method)&&r)throw new TypeError("Body not allowed for GET or HEAD requests");this._initBody(r)}function decode(e){var t=new FormData;return e.trim().split("&").forEach(function(e){if(e){var r=e.split("="),o=r.shift().replace(/\+/g," "),s=r.join("=").replace(/\+/g," ");t.append(decodeURIComponent(o),decodeURIComponent(s))}}),t}function parseHeaders(e){var t=new Headers;return e.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(e){var r=e.split(":"),o=r.shift().trim();if(o){var s=r.join(":").trim();t.append(o,s)}}),t}function Response(e,t){t||(t={}),this.type="default",this.status=void 0===t.status?200:t.status,this.ok=this.status>=200&&this.status<300,this.statusText="statusText"in t?t.statusText:"OK",this.headers=new Headers(t.headers),this.url=t.url||"",this._initBody(e)}Request.prototype.clone=function(){return new Request(this,{body:this._bodyInit})},Body.call(Request.prototype),Body.call(Response.prototype),Response.prototype.clone=function(){return new Response(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new Headers(this.headers),url:this.url})},Response.error=function(){var e=new Response(null,{status:0,statusText:""});return e.type="error",e};var redirectStatuses=[301,302,303,307,308];Response.redirect=function(e,t){if(-1===redirectStatuses.indexOf(t))throw new RangeError("Invalid status code");return new Response(null,{status:t,headers:{location:e}})};var DOMException=self.DOMException;try{new DOMException}catch(e){(DOMException=function(e,t){this.message=e,this.name=t;var r=Error(e);this.stack=r.stack}).prototype=Object.create(Error.prototype),DOMException.prototype.constructor=DOMException}function fetch(e,t){return new Promise(function(r,o){var s=new Request(e,t);if(s.signal&&s.signal.aborted)return o(new DOMException("Aborted","AbortError"));var n=new XMLHttpRequest;function i(){n.abort()}n.onload=function(){var e={status:n.status,statusText:n.statusText,headers:parseHeaders(n.getAllResponseHeaders()||"")};e.url="responseURL"in n?n.responseURL:e.headers.get("X-Request-URL");var t="response"in n?n.response:n.responseText;r(new Response(t,e))},n.onerror=function(){o(new TypeError("Network request failed"))},n.ontimeout=function(){o(new TypeError("Network request failed"))},n.onabort=function(){o(new DOMException("Aborted","AbortError"))},n.open(s.method,s.url,!0),"include"===s.credentials?n.withCredentials=!0:"omit"===s.credentials&&(n.withCredentials=!1),"responseType"in n&&support.blob&&(n.responseType="blob"),s.headers.forEach(function(e,t){n.setRequestHeader(t,e)}),s.signal&&(s.signal.addEventListener("abort",i),n.onreadystatechange=function(){4===n.readyState&&s.signal.removeEventListener("abort",i)}),n.send(void 0===s._bodyInit?null:s._bodyInit)})}fetch.polyfill=!0,self.fetch||(self.fetch=fetch,self.Headers=Headers,self.Request=Request,self.Response=Response); -------------------------------------------------------------------------------- /content/ClientApp/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import logger from '../utils/helpers/vuex-logger'; 5 | import counter from './modules/counter'; 6 | import weather from './modules/weather'; 7 | 8 | Vue.use(Vuex); 9 | 10 | const debugMode = process.env.NODE_ENV !== 'production'; 11 | 12 | export default new Vuex.Store({ 13 | modules: { 14 | counter, 15 | weather 16 | }, 17 | strict: debugMode, 18 | plugins: debugMode ? [logger()] : [] 19 | }); 20 | -------------------------------------------------------------------------------- /content/ClientApp/store/modules/counter.js: -------------------------------------------------------------------------------- 1 | import { DECREMENT_COUNTER, INCREMENT_COUNTER, RESET_COUNTER } from '../mutation-types'; 2 | 3 | export const COUNTER_OPERATIONS = { 4 | INCREMENT: 0, 5 | DECREMENT: 1, 6 | RESET: 2 7 | }; 8 | 9 | const INITIAL_STATE = { 10 | counter: 0 11 | }; 12 | 13 | const state = Object.assign({}, INITIAL_STATE); 14 | 15 | const getters = { 16 | counter: state => state.counter 17 | }; 18 | 19 | const mutations = { 20 | [INCREMENT_COUNTER]: state => state.counter++, 21 | 22 | [DECREMENT_COUNTER]: state => state.counter--, 23 | 24 | [RESET_COUNTER]: state => { 25 | state.counter = INITIAL_STATE.counter; 26 | } 27 | }; 28 | 29 | const actions = { 30 | operation: ({ commit }, operation) => { 31 | switch (operation) { 32 | case COUNTER_OPERATIONS.INCREMENT: 33 | commit(INCREMENT_COUNTER); 34 | break; 35 | case COUNTER_OPERATIONS.DECREMENT: 36 | commit(DECREMENT_COUNTER); 37 | break; 38 | case COUNTER_OPERATIONS.RESET: 39 | commit(RESET_COUNTER); 40 | break; 41 | default: 42 | console.error('No operation defined.'); 43 | } 44 | } 45 | }; 46 | 47 | export default { 48 | state, 49 | getters, 50 | mutations, 51 | actions 52 | }; 53 | -------------------------------------------------------------------------------- /content/ClientApp/store/modules/weather.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_CURRENT_PAGE, 3 | SET_FORECASTS, SET_PAGE_SIZE, 4 | SET_TOTAL_IN_SERVER 5 | } from '../mutation-types'; 6 | import ForecastService from '../../services/forecast-service'; 7 | 8 | const from = () => (state.tableOptions.currentPage - 1) * state.tableOptions.pageSize; 9 | 10 | const to = () => from() + state.tableOptions.pageSize; 11 | 12 | const INITIAL_STATE = { 13 | forecasts: [], 14 | tableOptions: { 15 | currentPage: 1, 16 | totalInServer: 0, 17 | pageSize: 10 18 | } 19 | }; 20 | 21 | const state = Object.assign({}, INITIAL_STATE); 22 | 23 | const getters = { 24 | forecasts: state => state.forecasts, 25 | 26 | hasForecasts: state => state.forecasts.length !== 0, 27 | 28 | tableOptions: state => state.tableOptions 29 | }; 30 | 31 | const mutations = { 32 | [SET_FORECASTS]: (state, forecasts) => { 33 | state.forecasts = forecasts; 34 | }, 35 | 36 | [SET_TOTAL_IN_SERVER]: (state, totalInServer) => { 37 | state.tableOptions.totalInServer = totalInServer; 38 | }, 39 | 40 | [SET_PAGE_SIZE]: (state, pageSize) => { 41 | state.tableOptions.pageSize = pageSize; 42 | }, 43 | 44 | [SET_CURRENT_PAGE]: (state, currentPage) => { 45 | state.tableOptions.currentPage = currentPage; 46 | } 47 | }; 48 | 49 | const actions = { 50 | fetchForecasts: async ({ commit }, page) => { 51 | commit(SET_CURRENT_PAGE, page); 52 | 53 | const response = await ForecastService.fetch(to(), from()); 54 | commit(SET_FORECASTS, response.data.forecasts); 55 | commit(SET_TOTAL_IN_SERVER, response.data.total); 56 | }, 57 | 58 | changePageSize: ({ commit }, pageSize) => { 59 | commit(SET_PAGE_SIZE, pageSize); 60 | } 61 | }; 62 | 63 | export default { 64 | state, 65 | getters, 66 | mutations, 67 | actions 68 | }; 69 | -------------------------------------------------------------------------------- /content/ClientApp/store/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'; 2 | export const DECREMENT_COUNTER = 'DECREMENT_COUNTER'; 3 | export const RESET_COUNTER = 'RESET_COUNTER'; 4 | export const SET_FORECASTS = 'SET_FORECASTS'; 5 | export const SET_TOTAL_IN_SERVER = 'SET_TOTAL_IN_SERVER'; 6 | export const SET_PAGE_SIZE = 'SET_PAGE_SIZE'; 7 | export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE'; 8 | -------------------------------------------------------------------------------- /content/ClientApp/styles/base/global.sass: -------------------------------------------------------------------------------- 1 | @import "../tools/variables" 2 | 3 | body 4 | width: 100% 5 | min-height: 100vh 6 | 7 | a 8 | color: $--color-primary 9 | -------------------------------------------------------------------------------- /content/ClientApp/styles/base/normalize.scss: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | Normalize.scss settings 3 | ========================================================================== */ 4 | /** 5 | * Includes legacy browser support IE6/7 6 | * 7 | * Set to false if you want to drop support for IE6 and IE7 8 | */ 9 | 10 | $legacy_browser_support: false !default; 11 | 12 | /* Base 13 | ========================================================================== */ 14 | 15 | /** 16 | * 1. Set default font family to sans-serif. 17 | * 2. Prevent iOS and IE text size adjust after device orientation change, 18 | * without disabling user zoom. 19 | * 3. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using 20 | * `em` units. 21 | */ 22 | 23 | html { 24 | font-family: sans-serif; /* 1 */ 25 | -ms-text-size-adjust: 100%; /* 2 */ 26 | -webkit-text-size-adjust: 100%; /* 2 */ 27 | @if $legacy_browser_support { 28 | *font-size: 100%; /* 3 */ 29 | } 30 | } 31 | 32 | /** 33 | * Remove default margin. 34 | */ 35 | 36 | body { 37 | margin: 0; 38 | } 39 | 40 | /* HTML5 display definitions 41 | ========================================================================== */ 42 | 43 | /** 44 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 45 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 46 | * and Firefox. 47 | * Correct `block` display not defined for `main` in IE 11. 48 | */ 49 | 50 | article, 51 | aside, 52 | details, 53 | figcaption, 54 | figure, 55 | footer, 56 | header, 57 | hgroup, 58 | main, 59 | menu, 60 | nav, 61 | section, 62 | summary { 63 | display: block; 64 | } 65 | 66 | /** 67 | * 1. Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. 68 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 69 | */ 70 | 71 | audio, 72 | canvas, 73 | progress, 74 | video { 75 | display: inline-block; /* 1 */ 76 | vertical-align: baseline; /* 2 */ 77 | @if $legacy_browser_support { 78 | *display: inline; 79 | *zoom: 1; 80 | } 81 | } 82 | 83 | /** 84 | * Prevents modern browsers from displaying `audio` without controls. 85 | * Remove excess height in iOS 5 devices. 86 | */ 87 | 88 | audio:not([controls]) { 89 | display: none; 90 | height: 0; 91 | } 92 | 93 | /** 94 | * Address `[hidden]` styling not present in IE 8/9/10. 95 | * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. 96 | */ 97 | 98 | [hidden], 99 | template { 100 | display: none; 101 | } 102 | 103 | /* Links 104 | ========================================================================== */ 105 | 106 | /** 107 | * Remove the gray background color from active links in IE 10. 108 | */ 109 | 110 | a { 111 | background-color: transparent; 112 | } 113 | 114 | /** 115 | * Improve readability of focused elements when they are also in an 116 | * active/hover state. 117 | */ 118 | 119 | a { 120 | &:active, &:hover { 121 | outline: 0; 122 | }; 123 | } 124 | 125 | /* Text-level semantics 126 | ========================================================================== */ 127 | 128 | /** 129 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 130 | */ 131 | 132 | abbr[title] { 133 | border-bottom: 1px dotted; 134 | } 135 | 136 | /** 137 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 138 | */ 139 | 140 | b, 141 | strong { 142 | font-weight: bold; 143 | } 144 | 145 | @if $legacy_browser_support { 146 | blockquote { 147 | margin: 1em 40px; 148 | } 149 | } 150 | 151 | /** 152 | * Address styling not present in Safari and Chrome. 153 | */ 154 | 155 | dfn { 156 | font-style: italic; 157 | } 158 | 159 | /** 160 | * Address variable `h1` font-size and margin within `section` and `article` 161 | * contexts in Firefox 4+, Safari, and Chrome. 162 | */ 163 | 164 | h1 { 165 | font-size: 2em; 166 | margin: 0.67em 0; 167 | } 168 | 169 | @if $legacy_browser_support { 170 | h2 { 171 | font-size: 1.5em; 172 | margin: 0.83em 0; 173 | } 174 | 175 | h3 { 176 | font-size: 1.17em; 177 | margin: 1em 0; 178 | } 179 | 180 | h4 { 181 | font-size: 1em; 182 | margin: 1.33em 0; 183 | } 184 | 185 | h5 { 186 | font-size: 0.83em; 187 | margin: 1.67em 0; 188 | } 189 | 190 | h6 { 191 | font-size: 0.67em; 192 | margin: 2.33em 0; 193 | } 194 | } 195 | 196 | /** 197 | * Addresses styling not present in IE 8/9. 198 | */ 199 | 200 | mark { 201 | background: #ff0; 202 | color: #000; 203 | } 204 | 205 | @if $legacy_browser_support { 206 | 207 | /** 208 | * Addresses margins set differently in IE 6/7. 209 | */ 210 | 211 | p, 212 | pre { 213 | *margin: 1em 0; 214 | } 215 | 216 | /* 217 | * Addresses CSS quotes not supported in IE 6/7. 218 | */ 219 | 220 | q { 221 | *quotes: none; 222 | } 223 | 224 | /* 225 | * Addresses `quotes` property not supported in Safari 4. 226 | */ 227 | 228 | q:before, 229 | q:after { 230 | content: ''; 231 | content: none; 232 | } 233 | } 234 | 235 | /** 236 | * Address inconsistent and variable font size in all browsers. 237 | */ 238 | 239 | small { 240 | font-size: 80%; 241 | } 242 | 243 | /** 244 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 245 | */ 246 | 247 | sub, 248 | sup { 249 | font-size: 75%; 250 | line-height: 0; 251 | position: relative; 252 | vertical-align: baseline; 253 | } 254 | 255 | sup { 256 | top: -0.5em; 257 | } 258 | 259 | sub { 260 | bottom: -0.25em; 261 | } 262 | 263 | @if $legacy_browser_support { 264 | 265 | /* ========================================================================== 266 | Lists 267 | ========================================================================== */ 268 | 269 | /* 270 | * Addresses margins set differently in IE 6/7. 271 | */ 272 | 273 | dl, 274 | menu, 275 | ol, 276 | ul { 277 | *margin: 1em 0; 278 | } 279 | 280 | dd { 281 | *margin: 0 0 0 40px; 282 | } 283 | 284 | /* 285 | * Addresses paddings set differently in IE 6/7. 286 | */ 287 | 288 | menu, 289 | ol, 290 | ul { 291 | *padding: 0 0 0 40px; 292 | } 293 | 294 | /* 295 | * Corrects list images handled incorrectly in IE 7. 296 | */ 297 | 298 | nav ul, 299 | nav ol { 300 | *list-style: none; 301 | *list-style-image: none; 302 | } 303 | 304 | } 305 | 306 | /* Embedded content 307 | ========================================================================== */ 308 | 309 | /** 310 | * 1. Remove border when inside `a` element in IE 8/9/10. 311 | * 2. Improves image quality when scaled in IE 7. 312 | */ 313 | 314 | img { 315 | border: 0; 316 | @if $legacy_browser_support { 317 | *-ms-interpolation-mode: bicubic; /* 2 */ 318 | } 319 | } 320 | 321 | /** 322 | * Correct overflow not hidden in IE 9/10/11. 323 | */ 324 | 325 | svg:not(:root) { 326 | overflow: hidden; 327 | } 328 | 329 | /* Grouping content 330 | ========================================================================== */ 331 | 332 | /** 333 | * Address margin not present in IE 8/9 and Safari. 334 | */ 335 | 336 | figure { 337 | margin: 1em 40px; 338 | } 339 | 340 | /** 341 | * Address differences between Firefox and other browsers. 342 | */ 343 | 344 | hr { 345 | box-sizing: content-box; 346 | height: 0; 347 | } 348 | 349 | /** 350 | * Contain overflow in all browsers. 351 | */ 352 | 353 | pre { 354 | overflow: auto; 355 | } 356 | 357 | /** 358 | * Address odd `em`-unit font size rendering in all browsers. 359 | * Correct font family set oddly in IE 6, Safari 4/5, and Chrome. 360 | */ 361 | 362 | code, 363 | kbd, 364 | pre, 365 | samp { 366 | font-family: monospace, monospace; 367 | @if $legacy_browser_support { 368 | _font-family: 'courier new', monospace; 369 | } 370 | font-size: 1em; 371 | } 372 | 373 | /* Forms 374 | ========================================================================== */ 375 | 376 | /** 377 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 378 | * styling of `select`, unless a `border` property is set. 379 | */ 380 | 381 | /** 382 | * 1. Correct color not being inherited. 383 | * Known issue: affects color of disabled elements. 384 | * 2. Correct font properties not being inherited. 385 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 386 | * 4. Improves appearance and consistency in all browsers. 387 | */ 388 | 389 | button, 390 | input, 391 | optgroup, 392 | select, 393 | textarea { 394 | color: inherit; /* 1 */ 395 | font: inherit; /* 2 */ 396 | margin: 0; /* 3 */ 397 | @if $legacy_browser_support { 398 | vertical-align: baseline; /* 3 */ 399 | *vertical-align: middle; /* 3 */ 400 | } 401 | } 402 | 403 | /** 404 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 405 | */ 406 | 407 | button { 408 | overflow: visible; 409 | } 410 | 411 | /** 412 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 413 | * All other form control elements do not inherit `text-transform` values. 414 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 415 | * Correct `select` style inheritance in Firefox. 416 | */ 417 | 418 | button, 419 | select { 420 | text-transform: none; 421 | } 422 | 423 | /** 424 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 425 | * and `video` controls. 426 | * 2. Correct inability to style clickable `input` types in iOS. 427 | * 3. Improve usability and consistency of cursor style between image-type 428 | * `input` and others. 429 | * 4. Removes inner spacing in IE 7 without affecting normal text inputs. 430 | * Known issue: inner spacing remains in IE 6. 431 | */ 432 | 433 | button, 434 | html input[type="button"], /* 1 */ 435 | input[type="reset"], 436 | input[type="submit"] { 437 | -webkit-appearance: button; /* 2 */ 438 | cursor: pointer; /* 3 */ 439 | @if $legacy_browser_support { 440 | *overflow: visible; /* 4 */ 441 | } 442 | } 443 | 444 | /** 445 | * Re-set default cursor for disabled elements. 446 | */ 447 | 448 | button[disabled], 449 | html input[disabled] { 450 | cursor: default; 451 | } 452 | 453 | /** 454 | * Remove inner padding and border in Firefox 4+. 455 | */ 456 | 457 | button::-moz-focus-inner, 458 | input::-moz-focus-inner { 459 | border: 0; 460 | padding: 0; 461 | } 462 | 463 | /** 464 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 465 | * the UA stylesheet. 466 | */ 467 | 468 | input { 469 | line-height: normal; 470 | } 471 | 472 | /** 473 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 474 | * 2. Remove excess padding in IE 8/9/10. 475 | * Known issue: excess padding remains in IE 6. 476 | */ 477 | 478 | input[type="checkbox"], 479 | input[type="radio"] { 480 | box-sizing: border-box; /* 1 */ 481 | padding: 0; /* 2 */ 482 | @if $legacy_browser_support { 483 | *height: 13px; /* 3 */ 484 | *width: 13px; /* 3 */ 485 | } 486 | } 487 | 488 | /** 489 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 490 | * `font-size` values of the `input`, it causes the cursor style of the 491 | * decrement button to change from `default` to `text`. 492 | */ 493 | 494 | input[type="number"]::-webkit-inner-spin-button, 495 | input[type="number"]::-webkit-outer-spin-button { 496 | height: auto; 497 | } 498 | 499 | /** 500 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 501 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. 502 | */ 503 | 504 | input[type="search"] { 505 | -webkit-appearance: textfield; /* 1 */ 506 | box-sizing: content-box; /* 2 */ 507 | } 508 | 509 | /** 510 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 511 | * Safari (but not Chrome) clips the cancel button when the search input has 512 | * padding (and `textfield` appearance). 513 | */ 514 | 515 | input[type="search"]::-webkit-search-cancel-button, 516 | input[type="search"]::-webkit-search-decoration { 517 | -webkit-appearance: none; 518 | } 519 | 520 | /** 521 | * Define consistent border, margin, and padding. 522 | */ 523 | 524 | fieldset { 525 | border: 1px solid #c0c0c0; 526 | margin: 0 2px; 527 | padding: 0.35em 0.625em 0.75em; 528 | } 529 | 530 | /** 531 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 532 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 533 | * 3. Corrects text not wrapping in Firefox 3. 534 | * 4. Corrects alignment displayed oddly in IE 6/7. 535 | */ 536 | 537 | legend { 538 | border: 0; /* 1 */ 539 | padding: 0; /* 2 */ 540 | @if $legacy_browser_support { 541 | white-space: normal; /* 3 */ 542 | *margin-left: -7px; /* 4 */ 543 | } 544 | } 545 | 546 | /** 547 | * Remove default vertical scrollbar in IE 8/9/10/11. 548 | */ 549 | 550 | textarea { 551 | overflow: auto; 552 | } 553 | 554 | /** 555 | * Don't inherit the `font-weight` (applied by a rule above). 556 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 557 | */ 558 | 559 | optgroup { 560 | font-weight: bold; 561 | } 562 | 563 | /* Tables 564 | ========================================================================== */ 565 | 566 | /** 567 | * Remove most spacing between table cells. 568 | */ 569 | 570 | table { 571 | border-collapse: collapse; 572 | border-spacing: 0; 573 | } 574 | 575 | td, 576 | th { 577 | padding: 0; 578 | } 579 | -------------------------------------------------------------------------------- /content/ClientApp/styles/main.sass: -------------------------------------------------------------------------------- 1 | // tooling: variables, mixins, functions 2 | @import "./tools/variables" 3 | 4 | // base application styles 5 | @import "./base/normalize" 6 | @import "./base/global" 7 | 8 | // 3th imports or overrides 9 | @import "./vendors/element" 10 | -------------------------------------------------------------------------------- /content/ClientApp/styles/tools/variables.sass: -------------------------------------------------------------------------------- 1 | /* theme color */ 2 | $--color-primary: teal 3 | 4 | @import "~element-ui/packages/theme-chalk/src/common/var" 5 | -------------------------------------------------------------------------------- /content/ClientApp/styles/vendors/element.scss: -------------------------------------------------------------------------------- 1 | $--font-path: '~element-ui/lib/theme-chalk/fonts'; 2 | 3 | @import "~element-ui/packages/theme-chalk/src/index"; 4 | -------------------------------------------------------------------------------- /content/ClientApp/utils/helpers/functions.js: -------------------------------------------------------------------------------- 1 | export const find = (list, f) => list.filter(f)[0]; 2 | 3 | export const deepCopy = (obj, cache = []) => { 4 | if (obj === null || typeof obj !== 'object') { 5 | return obj; 6 | } 7 | 8 | const hit = find(cache, c => c.original === obj); 9 | if (hit) { 10 | return hit.copy; 11 | } 12 | 13 | const copy = Array.isArray(obj) ? [] : {}; 14 | 15 | cache.push({ 16 | original: obj, 17 | copy 18 | }); 19 | 20 | Object.keys(obj).forEach(key => { 21 | copy[key] = deepCopy(obj[key], cache); 22 | }); 23 | 24 | return copy; 25 | }; 26 | 27 | export const forEachValue = (obj, fn) => { 28 | Object.keys(obj).forEach(key => fn(obj[key], key)); 29 | }; 30 | 31 | export const isObject = (obj) => obj !== null && typeof obj === 'object'; 32 | 33 | export const isPromise = (val) => val && typeof val.then === 'function'; 34 | 35 | export const assert = (condition, msg) => { 36 | if (!condition) throw new Error(`[vuex] ${msg}`); 37 | }; 38 | 39 | export const repeat = (str, times) => (new Array(times + 1)).join(str); 40 | 41 | export const pad = (num, maxLength) => repeat('0', maxLength - num.toString().length) + num; 42 | -------------------------------------------------------------------------------- /content/ClientApp/utils/helpers/notification.js: -------------------------------------------------------------------------------- 1 | export class Notification { 2 | /** 3 | * Show success notification 4 | * 5 | * @param {Object} vueInstance - Vue instance 6 | * @param {String} message - Message which to display on Notification 7 | */ 8 | static success(vueInstance, message) { 9 | vueInstance.$notify({ 10 | type: 'success', 11 | title: 'Success', 12 | message, 13 | duration: 3500 14 | }); 15 | } 16 | 17 | /** 18 | * Show error notification 19 | * 20 | * @param {Object} vueInstance - Vue instance 21 | * @param {String} message - Message which to display on Notification 22 | */ 23 | static error(vueInstance, message) { 24 | vueInstance.$notify({ 25 | type: 'error', 26 | title: 'Something went wrong', 27 | message, 28 | duration: 5000 29 | }); 30 | } 31 | 32 | /** 33 | * Show warn notification 34 | * 35 | * @param {Object} vueInstance - Vue instance 36 | * @param {String} message - Message which to display on Notification 37 | */ 38 | static warning(vueInstance, message) { 39 | vueInstance.$notify({ 40 | type: 'warning', 41 | title: 'Something went wrong', 42 | message, 43 | duration: 5000 44 | }); 45 | } 46 | 47 | /** 48 | * Show info notification 49 | * 50 | * @param {Object} vueInstance - Vue instance 51 | * @param {String} message - Message which to display on Notification 52 | */ 53 | static info(vueInstance, message) { 54 | vueInstance.$notify({ 55 | type: 'info', 56 | title: 'Info', 57 | message, 58 | duration: 5000 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /content/ClientApp/utils/helpers/table-column-composer.js: -------------------------------------------------------------------------------- 1 | // This is a helper to compose columns to the el-table dynamically 2 | 3 | const unCamelCase = str => str 4 | .replace(/([a-z])([A-Z])/g, '$1 $2') 5 | .replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3') 6 | .replace(/^./, str => str.toUpperCase()); 7 | 8 | const createLabels = (property) => unCamelCase(property); 9 | 10 | /** 11 | * This is necessary because the table component of element-ui, when in a v-for, sets the 12 | * first column to the end. So, here, we put the real last option to start. 13 | * @param columns - The columns of the table 14 | */ 15 | const resolveOrder = (columns) => { 16 | const lastOption = columns[columns.length - 1]; 17 | 18 | const oldOptions = columns.filter(op => op !== lastOption); 19 | const newOptions = []; 20 | 21 | newOptions.push(lastOption); 22 | newOptions.push(...oldOptions); 23 | 24 | return newOptions; 25 | }; 26 | 27 | class TableColumnComposer { 28 | /** 29 | * Compose the column array by receiving the column objects. 30 | * @param columns - The array of columns. 31 | * @returns {Array} - The reordered array of columns. 32 | */ 33 | static composeColumns(columns) { 34 | return resolveOrder(columns); 35 | } 36 | 37 | /** 38 | * Compose the array of columns for some object. 39 | * @param model - The object showed in the table. CANNOT have inner objects. 40 | * @param options - Object with another options for the columns. 41 | * Each option is an array for each model attribute. 42 | * @returns {Array} - The reordered array of columns. 43 | */ 44 | static compose(model, options) { 45 | const columns = []; 46 | 47 | const modelAsArray = Object.entries(model).map(o => o[0]); 48 | 49 | modelAsArray.forEach(property => { 50 | columns.push(this.newColumn( 51 | options && options.labels && options.labels.length === modelAsArray.length 52 | ? options.labels[modelAsArray.indexOf(property)] 53 | : createLabels(property), 54 | property, 55 | options 56 | ? options[modelAsArray.indexOf(property)] 57 | : null 58 | )); 59 | }); 60 | 61 | return resolveOrder(columns); 62 | } 63 | 64 | /** 65 | * Creates an column. 66 | * @param label - The label of the column. 67 | * @param property - The property, i.e, the attribute name of the object showed. 68 | * @param options - Object with additional options for the 69 | * column, as 'width', 'type' and 'showOverflowTooltip'. 70 | * @returns {{property, label, type, showOverflowTooltip}} - A column. 71 | */ 72 | static newColumn(label, property, options) { 73 | return { 74 | label, 75 | property, 76 | type: options && options.type || 'name', 77 | showOverflowTooltip: options && options.showOverflowTooltip || false 78 | }; 79 | } 80 | } 81 | 82 | export default TableColumnComposer; 83 | -------------------------------------------------------------------------------- /content/ClientApp/utils/helpers/vuex-logger.js: -------------------------------------------------------------------------------- 1 | import { deepCopy, pad } from './functions'; 2 | 3 | /* eslint-disable */ 4 | export default function logger({ 5 | collapsed = true, 6 | filter = (mutation, stateBefore, stateAfter) => true, 7 | transformer = state => state, 8 | mutationTransformer = mut => mut, 9 | logger = console 10 | } = {}) { 11 | return store => { 12 | let prevState = deepCopy(store.state); 13 | 14 | store.subscribe((mutation, state) => { 15 | if (typeof logger === 'undefined') { 16 | return; 17 | } 18 | const nextState = deepCopy(state); 19 | 20 | if (filter(mutation, prevState, nextState)) { 21 | const time = new Date(); 22 | const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`; 23 | const formattedMutation = mutationTransformer(mutation); 24 | const message = `mutation ${mutation.type}${formattedTime}`; 25 | const startMessage = collapsed 26 | ? logger.groupCollapsed 27 | : logger.group; 28 | 29 | try { 30 | startMessage.call(logger, message); 31 | } catch (e) { 32 | console.error(message); 33 | } 34 | 35 | logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState)); 36 | logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation); 37 | logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState)); 38 | 39 | try { 40 | logger.groupEnd(); 41 | } catch (e) { 42 | logger.log('—— log end ——'); 43 | } 44 | } 45 | 46 | prevState = nextState; 47 | }); 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /content/Controllers/WeatherController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading; 3 | using AspDotnetVueJs.Providers; 4 | using Microsoft.AspNetCore.Cors; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace AspDotnetVueJs.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | public class WeatherController : ControllerBase 11 | { 12 | private readonly IWeatherProvider _weatherProvider; 13 | 14 | public WeatherController(IWeatherProvider weatherProvider) 15 | { 16 | _weatherProvider = weatherProvider; 17 | } 18 | 19 | [HttpGet("[action]")] 20 | public IActionResult Forecasts([FromQuery(Name = "from")] int from = 0, [FromQuery(Name = "to")] int to = 4) 21 | { 22 | var quantity = to - from; 23 | 24 | // We should also avoid going too far in the list. 25 | if (quantity <= 0) return BadRequest("You cannot have the 'to' parameter higher than 'from' parameter."); 26 | 27 | if (from < 0) return BadRequest("You cannot go in the negative with the 'from' parameter"); 28 | 29 | var allForecasts = _weatherProvider.GetForecasts(); 30 | var result = new 31 | { 32 | Total = allForecasts.Count, 33 | Forecasts = allForecasts.Skip(from).Take(quantity).ToArray() 34 | }; 35 | 36 | Thread.Sleep(2000); 37 | 38 | return Ok(result); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /content/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the container with Source code compiled 2 | FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine3.8 as buildenv 3 | WORKDIR /source 4 | RUN apk add --update nodejs nodejs-npm 5 | COPY *.csproj . 6 | RUN dotnet restore 7 | COPY . . 8 | # Publishing will also restore (install) the npm packages. 9 | RUN dotnet publish -c Release -o /app/ -r linux-musl-x64 10 | 11 | # Stage 2 - Creating Image for compiled app 12 | FROM mcr.microsoft.com/dotnet/core/runtime:2.2-alpine3.8 as baseimage 13 | RUN addgroup -S coreApp && adduser -S -G coreApp coreApp 14 | 15 | # Define other environment variable if needed. 16 | ENV ASPNETCORE_URLS=http://+:$port 17 | 18 | WORKDIR /app 19 | COPY --from=buildenv /app . 20 | RUN chown -R coreApp:coreApp /app 21 | 22 | # Replace the application name if required. 23 | ENTRYPOINT ["dotnet", "AspDotnetVueJs.dll"] 24 | EXPOSE $port 25 | -------------------------------------------------------------------------------- /content/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using AspDotnetVueJs.Providers; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace AspDotnetVueJs.Extensions 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static IServiceCollection AddWeather(this IServiceCollection services) 9 | { 10 | services.AddSingleton(); 11 | 12 | return services; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /content/Models/WeatherForecast.cs: -------------------------------------------------------------------------------- 1 | namespace AspDotnetVueJs.Models 2 | { 3 | public class WeatherForecast 4 | { 5 | public string DateFormatted { get; set; } 6 | 7 | public string Summary { get; set; } 8 | 9 | public int TemperatureC { get; set; } 10 | 11 | public int TemperatureF => 32 + (int) (TemperatureC / 0.5556); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Hosting; 4 | 5 | namespace AspDotnetVueJs 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateHostBuilder(args).Build().Run(); 12 | } 13 | 14 | public static IHostBuilder CreateHostBuilder(string[] args) => 15 | Host.CreateDefaultBuilder(args) 16 | .ConfigureWebHostDefaults(webBuilder => 17 | { 18 | webBuilder.UseStartup(); 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /content/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:36025", 8 | "sslPort": 44353 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "AspDotnetVueJS": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "", 24 | "applicationUrl": "http://localhost:5000", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /content/Providers/IWeatherProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using AspDotnetVueJs.Models; 3 | 4 | namespace AspDotnetVueJs.Providers 5 | { 6 | public interface IWeatherProvider 7 | { 8 | List GetForecasts(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /content/Providers/WeatherProviderFake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using AspDotnetVueJs.Models; 5 | 6 | namespace AspDotnetVueJs.Providers 7 | { 8 | public class WeatherProviderFake : IWeatherProvider 9 | { 10 | private readonly string[] summaries = 11 | { 12 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 13 | }; 14 | 15 | public WeatherProviderFake() 16 | { 17 | Initialize(100); 18 | } 19 | 20 | private List WeatherForecasts { get; set; } 21 | 22 | public List GetForecasts() 23 | { 24 | return WeatherForecasts; 25 | } 26 | 27 | private void Initialize(int quantity) 28 | { 29 | var rng = new Random(); 30 | WeatherForecasts = Enumerable.Range(1, quantity).Select(index => new WeatherForecast 31 | { 32 | DateFormatted = DateTime.Now.AddDays(index).ToString("d"), 33 | TemperatureC = rng.Next(-20, 55), 34 | Summary = summaries[rng.Next(summaries.Length)] 35 | }).ToList(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /content/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using System.Reflection; 5 | using AspDotnetVueJs.Extensions; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.AspNetCore.ResponseCompression; 10 | using Microsoft.AspNetCore.SpaServices.Webpack; 11 | using Microsoft.Extensions.Configuration; 12 | using Microsoft.Extensions.DependencyInjection; 13 | using Microsoft.Extensions.Hosting; 14 | using Swashbuckle.AspNetCore.Swagger; 15 | using Westwind.AspNetCore.LiveReload; 16 | 17 | [assembly: ApiConventionType(typeof(DefaultApiConventions))] 18 | 19 | namespace AspDotnetVueJs 20 | { 21 | public class Startup 22 | { 23 | public Startup(IConfiguration configuration) 24 | { 25 | Configuration = configuration; 26 | } 27 | 28 | public static IConfiguration Configuration { get; private set; } 29 | 30 | public void ConfigureServices(IServiceCollection services) 31 | { 32 | services.AddLiveReload(config => 33 | { 34 | }); 35 | 36 | services 37 | .AddMvc().AddNewtonsoftJson() 38 | .SetCompatibilityVersion(CompatibilityVersion.Version_3_0); 39 | 40 | services.AddSwaggerGen(c => 41 | { 42 | c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo 43 | { 44 | Title = Configuration["App:Title"], 45 | Description = Configuration["App:Description"], 46 | TermsOfService = new Uri(Configuration["App:TermsOfService"]), 47 | Version = Configuration["App:Version"] 48 | }); 49 | 50 | var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; 51 | var xmlPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location), xmlFile); 52 | c.IncludeXmlComments(xmlPath); 53 | }); 54 | 55 | services.AddCors(options => 56 | { 57 | /* 58 | Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery. 59 | The CORS service returns an invalid CORS response when an app is configured with both methods. 60 | */ 61 | options.AddPolicy("CorsPolicy", 62 | builder => builder.AllowAnyOrigin() 63 | .AllowAnyMethod() 64 | .AllowAnyHeader() 65 | //.AllowCredentials() 66 | ); 67 | }); 68 | 69 | services.Configure(options => 70 | options.Level = CompressionLevel.Optimal); 71 | 72 | services.AddResponseCompression(options => 73 | { 74 | #if (!NoHttps) 75 | options.EnableForHttps = true; 76 | #endif 77 | }); 78 | 79 | services.AddSpaStaticFiles(config => { config.RootPath = "wwwroot/"; }); 80 | 81 | // Example with dependency injection for a data provider. 82 | services.AddWeather(); 83 | } 84 | 85 | [System.Obsolete] 86 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 87 | { 88 | if (env.IsDevelopment()) 89 | { 90 | app.UseLiveReload(); 91 | app.UseDeveloperExceptionPage(); 92 | } 93 | else 94 | { 95 | app.UseExceptionHandler("/Error"); 96 | #if (!NoHttps) 97 | app.UseHsts(); 98 | } 99 | 100 | app.UseHttpsRedirection(); 101 | #else 102 | } 103 | #endif 104 | 105 | //app.UseResponseCompression(); 106 | 107 | app.UseSwagger(); 108 | app.UseSwaggerUI(c => 109 | { 110 | c.SwaggerEndpoint( 111 | $"{Configuration["BaseUriPath"]}/swagger/v1/swagger.json", 112 | $"{Configuration["App:Title"]} {Configuration["App:Version"]}" 113 | ); 114 | }); 115 | 116 | //app.UseDefaultFiles(); 117 | app.UseStaticFiles(); 118 | app.UseSpaStaticFiles(); 119 | app.UseRouting(); 120 | app.UseCors("CorsPolicy"); 121 | app.UseEndpoints(endpoints => 122 | { 123 | endpoints.MapControllerRoute( 124 | name: "default", 125 | pattern: "{controller}/{action=Index}/{id?}"); 126 | }); 127 | 128 | app.UseSpa(spa => 129 | { 130 | spa.Options.SourcePath = "ClientApp"; 131 | 132 | if (env.IsDevelopment()) 133 | spa.ApplicationBuilder.UseWebpackDevMiddleware( 134 | new WebpackDevMiddlewareOptions 135 | { 136 | HotModuleReplacement = true, 137 | ConfigFile = "./ClientApp/build/webpack.config.js" 138 | }); 139 | }); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /content/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | }, 9 | "BaseUriPath": "", 10 | "Environment": "dev", 11 | "GenerateMapFiles": "false", 12 | "WebRoot": "null", 13 | "Port": 5000, 14 | "LiveReload": { 15 | "LiveReloadEnabled": true, 16 | "ClientFileExtensions": ".cshtml,.css,.js,.htm,.html,.ts,.wc", 17 | "ServerRefreshTimeout": 3000, 18 | "WebSocketUrl": "/__livereload" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /content/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "App": { 11 | "Title": "ASP.NET VueJs | Template", 12 | "Description": "Template com .NET Core e VueJs", 13 | "Version": "3.0.0", 14 | "TermsOfService": "https://github.com/hvpaiva/aspdotnet-vuejs" 15 | }, 16 | "ApiUrl": "http://localhost:5000", 17 | "BaseUriPath": "", 18 | "Environment": "prod", 19 | "GenerateMapFiles": "true", 20 | "LiveReload": { 21 | "LiveReloadEnabled": false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /content/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aspdotnet-vuejs", 3 | "description": "ASP.NET Core & VueJS", 4 | "author": "Highlander Paiva", 5 | "repository": { 6 | "url": "https://github.com/hvpaiva/aspdotnet-vuejs" 7 | }, 8 | "license": "MIT", 9 | "scripts": { 10 | "build": "webpack --config ./ClientApp/build/webpack.config.js --hide-modules --progress --colors", 11 | "build:dev": "cross-env ASPNETCORE_ENVIRONMENT=Development NODE_ENV=development npm run build", 12 | "build:prod": "cross-env ASPNETCORE_ENVIRONMENT=Production NODE_ENV=production npm run build", 13 | "update-packages": "npx npm-check -u", 14 | "lint": "eslint ./ClientApp/ --ext .js,.vue --fix" 15 | }, 16 | "dependencies": { 17 | "axios": "^0.18.0", 18 | "vue": "^2.6.8", 19 | "vue-router": "^3.0.2", 20 | "vuex": "^3.1.0", 21 | "vuex-router-sync": "^5.0.0", 22 | "lodash": "^4.17.11" 23 | }, 24 | "devDependencies": { 25 | "cross-env": "^5.2.0", 26 | "@babel/core": "^7.3.4", 27 | "@babel/plugin-proposal-class-properties": "^7.0.0", 28 | "@babel/plugin-proposal-decorators": "^7.0.0", 29 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0", 30 | "@babel/plugin-proposal-function-sent": "^7.0.0", 31 | "@babel/plugin-proposal-json-strings": "^7.0.0", 32 | "@babel/plugin-proposal-numeric-separator": "^7.0.0", 33 | "@babel/plugin-proposal-throw-expressions": "^7.0.0", 34 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 35 | "@babel/plugin-syntax-import-meta": "^7.0.0", 36 | "@babel/plugin-transform-async-to-generator": "^7.3.4", 37 | "@babel/plugin-transform-runtime": "^7.3.4", 38 | "@babel/preset-env": "^7.3.4", 39 | "@babel/register": "^7.0.0", 40 | "@babel/runtime": "^7.3.4", 41 | "@fortawesome/fontawesome-svg-core": "^1.2.13", 42 | "@fortawesome/free-brands-svg-icons": "^5.7.0", 43 | "@fortawesome/free-solid-svg-icons": "^5.7.0", 44 | "@fortawesome/vue-fontawesome": "^0.1.5", 45 | "aspnet-webpack": "^3.0.0", 46 | "babel-eslint": "^10.0.1", 47 | "babel-loader": "^8.0.5", 48 | "babel-preset-env": "^1.7.0", 49 | "copy-webpack-plugin": "^5.0.0", 50 | "css-loader": "^2.1.0", 51 | "element-ui": "^2.7.0", 52 | "eslint": "^5.15.1", 53 | "eslint-config-airbnb": "^17.1.0", 54 | "eslint-plugin-import": "^2.16.0", 55 | "eslint-plugin-jsx-a11y": "^6.1.1", 56 | "eslint-plugin-node": "^8.0.1", 57 | "eslint-plugin-promise": "^4.0.1", 58 | "eslint-plugin-react": "^7.11.0", 59 | "eslint-plugin-vue": "^5.2.2", 60 | "file-loader": "^3.0.1", 61 | "font-awesome": "^4.7.0", 62 | "html-webpack-plugin": "^3.2.0", 63 | "mini-css-extract-plugin": "^0.5.0", 64 | "node-sass": "^4.11.0", 65 | "optimize-css-assets-webpack-plugin": "^5.0.1", 66 | "pug": "^2.0.3", 67 | "pug-plain-loader": "^1.0.0", 68 | "rimraf": "^2.6.3", 69 | "sass-loader": "^7.1.0", 70 | "uglifyjs-webpack-plugin": "^2.1.2", 71 | "url-loader": "^1.1.2", 72 | "vue-loader": "^15.7.0", 73 | "vue-style-loader": "^4.1.2", 74 | "vue-template-compiler": "^2.6.8", 75 | "webpack": "^4.29.6", 76 | "webpack-cli": "^3.2.3", 77 | "webpack-dev-middleware": "^3.6.0", 78 | "webpack-hot-middleware": "^2.24.3" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /content/wwwroot/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hvpaiva/aspdotnet-vuejs/e7bf3c5ed78e95f0f5a9a392b8dc32fdfdbe9b16/content/wwwroot/.gitkeep --------------------------------------------------------------------------------