{"ArticleId":null,"Name":"Development setup","Content":"\u003Cp\u003EThis article takes you from an empty machine to a GrandNode storefront running from source in your IDE, with breakpoints working in core code and in plugins. Only two things are required: the .NET SDK and a MongoDB server. Node.js is needed only when you change frontend sources.\u003C/p\u003E\n\n\u003Ch2 id=\u0022prerequisites\u0022\u003EPrerequisites\u003C/h2\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\u003Ctr\u003E\u003Cth\u003ETool\u003C/th\u003E\u003Cth\u003EVersion\u003C/th\u003E\u003Cth\u003ENeeded for\u003C/th\u003E\u003C/tr\u003E\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\u003Ctd\u003E.NET SDK\u003C/td\u003E\u003Ctd\u003E10.0 \u2014 the exact feature band is pinned in \u003Ccode\u003Eglobal.json\u003C/code\u003E\u003C/td\u003E\u003Ctd\u003Ebuilding and running everything\u003C/td\u003E\u003C/tr\u003E\n\u003Ctr\u003E\u003Ctd\u003EMongoDB\u003C/td\u003E\u003Ctd\u003E4.0 or newer\u003C/td\u003E\u003Ctd\u003Ethe database: a local server, a Docker container or a MongoDB Atlas cluster\u003C/td\u003E\u003C/tr\u003E\n\u003Ctr\u003E\u003Ctd\u003ENode.js and npm\u003C/td\u003E\u003Ctd\u003E20 LTS or newer\u003C/td\u003E\u003Ctd\u003Eonly when you change the storefront (\u003Ccode\u003Evueapp\u003C/code\u003E) or the panel frontend (\u003Ccode\u003Eadminapp\u003C/code\u003E)\u003C/td\u003E\u003C/tr\u003E\n\u003Ctr\u003E\u003Ctd\u003EIDE\u003C/td\u003E\u003Ctd\u003EVisual Studio, JetBrains Rider or VS Code\u003C/td\u003E\u003Ctd\u003Eoptional\u003C/td\u003E\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Cp\u003EThe quickest MongoDB for development is a container:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Edocker run -d -p 127.0.0.1:27017:27017 --name mongodb mongo\u003C/code\u003E\u003C/pre\u003E\n\n\u003Ch2 id=\u0022clone-and-build\u0022\u003EClone and build\u003C/h2\u003E\n\u003Col\u003E\n\u003Cli\u003EClone the repository. \u003Ccode\u003Edevelop\u003C/code\u003E is the integration branch where new work lands; \u003Ccode\u003Emain\u003C/code\u003E holds the latest stable release.\n\u003Cpre\u003E\u003Ccode\u003Egit clone https://github.com/grandnode/grandnode2.git\ncd grandnode2\ngit checkout develop\u003C/code\u003E\u003C/pre\u003E\u003C/li\u003E\n\u003Cli\u003ERestore and build the whole solution:\n\u003Cpre\u003E\u003Ccode\u003Edotnet restore GrandNode.slnx\ndotnet build GrandNode.slnx\u003C/code\u003E\u003C/pre\u003E\u003C/li\u003E\n\u003C/ol\u003E\n\u003Cp\u003EBuilding the solution is important the first time. \u003Ccode\u003EGrand.Web\u003C/code\u003E does not reference the modules and plugins; each of them copies itself into \u003Ccode\u003Esrc/Web/Grand.Web/Modules\u003C/code\u003E or \u003Ccode\u003Esrc/Web/Grand.Web/Plugins\u003C/code\u003E when it is built. After one full build you can start the web project on its own.\u003C/p\u003E\n\n\u003Ch2 id=\u0022run\u0022\u003ERun\u003C/h2\u003E\n\u003Cpre\u003E\u003Ccode\u003Edotnet run --project src/Web/Grand.Web\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003EThe Kestrel launch profile listens on \u003Ccode\u003Ehttps://localhost:5001\u003C/code\u003E and \u003Ccode\u003Ehttp://localhost:5000\u003C/code\u003E; the IIS Express profile uses \u003Ccode\u003Ehttps://localhost:44350\u003C/code\u003E. Both profiles set \u003Ccode\u003EASPNETCORE_ENVIRONMENT=Development\u003C/code\u003E. Keep it that way when you start the app another way: without it the static web assets manifest is not used, files under \u003Ccode\u003E_content/\u003C/code\u003E return 404 and the admin panel loads without CSS and JavaScript.\u003C/p\u003E\n\n\u003Ch2 id=\u0022installer\u0022\u003EFirst run: the installer\u003C/h2\u003E\n\u003Cp\u003EOn the first run the application redirects to \u003Ccode\u003E/install\u003C/code\u003E. Enter the MongoDB connection string, for example \u003Ccode\u003Emongodb://localhost/grandnode\u003C/code\u003E, the administrator e-mail and password, and choose whether to load the sample data. The installer writes the connection string to \u003Ccode\u003Esrc/Web/Grand.Web/App_Data/Settings.cfg\u003C/code\u003E, which git ignores. To start over against a fresh database, stop the app, delete that file and run again.\u003C/p\u003E\n\n\u003Ch2 id=\u0022configuration\u0022\u003EConfiguration\u003C/h2\u003E\n\u003Cp\u003ERuntime configuration lives in \u003Ccode\u003Esrc/Web/Grand.Web/App_Data/appsettings.json\u003C/code\u003E. Any value can be overridden with an environment variable using a double underscore for nesting, for example \u003Ccode\u003EFeatureManagement__Grand.Module.Api=true\u003C/code\u003E or \u003Ccode\u003ERedis__RedisPubSubEnabled=true\u003C/code\u003E. Sections you will meet as a developer:\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\u003Ctr\u003E\u003Cth\u003ESection\u003C/th\u003E\u003Cth\u003EWhat it does\u003C/th\u003E\u003C/tr\u003E\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\u003Ctd\u003E\u003Ccode\u003EFeatureManagement\u003C/code\u003E\u003C/td\u003E\u003Ctd\u003ETurns modules on or off: Installer, Migration, ScheduledTasks and Api (the API is off by default).\u003C/td\u003E\u003C/tr\u003E\n\u003Ctr\u003E\u003Ctd\u003E\u003Ccode\u003EBackendAPI\u003C/code\u003E, \u003Ccode\u003EFrontendAPI\u003C/code\u003E\u003C/td\u003E\u003Ctd\u003EJWT settings for the REST API \u2014 see \u003Ca href=\u0022/developers-rest-api\u0022\u003EThe REST API\u003C/a\u003E.\u003C/td\u003E\u003C/tr\u003E\n\u003Ctr\u003E\u003Ctd\u003E\u003Ccode\u003ERedis\u003C/code\u003E\u003C/td\u003E\u003Ctd\u003ECache synchronisation between instances and data-protection key storage.\u003C/td\u003E\u003C/tr\u003E\n\u003Ctr\u003E\u003Ctd\u003E\u003Ccode\u003EExtensions\u003C/code\u003E\u003C/td\u003E\u003Ctd\u003EPlugin loading options: \u003Ccode\u003EPluginSkipLoadingPattern\u003C/code\u003E, \u003Ccode\u003EDisableUploadExtensions\u003C/code\u003E, shadow copying and Roslyn scripts.\u003C/td\u003E\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\n\u003Ch2 id=\u0022debugging\u0022\u003EDebugging\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003ESet \u003Cstrong\u003EGrand.Web\u003C/strong\u003E as the startup project and press F5. Breakpoints in core, business and web projects work immediately.\u003C/li\u003E\n\u003Cli\u003EBreakpoints in a plugin work as long as the plugin was built in the same configuration (Debug) \u2014 its symbols are copied next to the DLL in \u003Ccode\u003EGrand.Web/Plugins/\u0026lt;SystemName\u0026gt;\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EPlugin views are compiled into the plugin DLL.\u003C/strong\u003E After editing a \u003Ccode\u003E.cshtml\u003C/code\u003E file in a plugin or theme, rebuild that plugin (\u003Ccode\u003Edotnet build src/Plugins/Theme.Modern\u003C/code\u003E) and restart the site. Razor runtime compilation covers only \u003Ccode\u003EGrand.Web\u003C/code\u003E\u0027s own views. Stop the site before rebuilding a plugin, or the build fails on a locked DLL.\u003C/li\u003E\n\u003Cli\u003EFor a multi-instance setup with Redis, run the Aspire host in \u003Ccode\u003Esrc/Aspire/Aspire.AppHost\u003C/code\u003E: it starts MongoDB and Redis in containers and two replicas of the web app that share one database.\u003C/li\u003E\n\u003C/ul\u003E\n\n\u003Ch2 id=\u0022tests\u0022\u003ERunning the tests\u003C/h2\u003E\n\u003Cpre\u003E\u003Ccode\u003Edotnet test src/Tests/Grand.Business.Catalog.Tests\ndotnet test GrandNode.slnx\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003ETests use MSTest and Moq. Run the project closest to your change while iterating and the whole solution before you open a pull request.\u003C/p\u003E\n\n\u003Ch2 id=\u0022frontend\u0022\u003EFrontend bundles\u003C/h2\u003E\n\u003Cp\u003EThe storefront UI (Vue 3, Bootstrap 5) lives in \u003Ccode\u003Esrc/Web/Grand.Web/vueapp\u003C/code\u003E; the panels are built from \u003Ccode\u003Esrc/Web/Grand.SharedUIResources/adminapp\u003C/code\u003E. The built bundles are committed to the repository, which is why you can run the shop without Node. If you change anything under \u003Ccode\u003Evueapp/src\u003C/code\u003E or \u003Ccode\u003Ewwwroot/theme/css\u003C/code\u003E, rebuild and commit the bundles with the source change:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Ecd src/Web/Grand.Web/vueapp\nnpm install\nnpm run build\u003C/code\u003E\u003C/pre\u003E\n\n\u003Ch2 id=\u0022docker\u0022\u003ERunning the Docker image instead\u003C/h2\u003E\n\u003Cp\u003EIf you only need a running instance to develop against, for example for API work, use the published image:\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003Edocker run -d -p 127.0.0.1:27017:27017 --name mongodb mongo\ndocker run -d -p 80:8080 --name grandnode2 --link mongodb:mongo grandnode/grandnode2\u003C/code\u003E\u003C/pre\u003E\n\n\u003Ch2 id=\u0022tips\u0022\u003ETips and common mistakes\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003EA plugin you just added does not appear: it was not built, or its output path does not point into \u003Ccode\u003EGrand.Web/Plugins\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EThe admin panel has no styles: \u003Ccode\u003EASPNETCORE_ENVIRONMENT\u003C/code\u003E is not \u003Ccode\u003EDevelopment\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EA view change in a plugin does nothing: the plugin was not rebuilt.\u003C/li\u003E\n\u003C/ul\u003E\n\n\u003Ch2 id=\u0022related\u0022\u003ERelated\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ca href=\u0022/developers-architecture-overview\u0022\u003EArchitecture overview\u003C/a\u003E\u003C/li\u003E\n\u003Cli\u003E\u003Ca href=\u0022/developers-contributing\u0022\u003EContributing\u003C/a\u003E\u003C/li\u003E\n\u003Cli\u003EInstalling for production: \u003Ca href=\u0022/docs-getting-started\u0022\u003EGetting started\u003C/a\u003E\u003C/li\u003E\n\u003C/ul\u003E","ParentCategoryId":"6abdec6d83d2816248229f65","SeName":"developers-development-setup","MetaKeywords":null,"MetaDescription":"Clone, build and run GrandNode from source: .NET SDK, MongoDB, the installer, debugging, plugin rebuilds and the frontend bundles.","MetaTitle":null,"AllowComments":false,"Captcha":{"ReCaptchaChallengeField":null,"ReCaptchaResponseField":null,"ReCaptchaResponseValue":null,"ReCaptchaResponse":null},"RelatedArticles":[],"CategoryBreadcrumb":[{"Name":"For developers","Description":null,"IsCurrent":false,"Children":null,"Parent":null,"SeName":"docs-developers","Id":"6abdec6d83d2816248229f65","UserFields":[]}],"AddNewComment":{"CommentText":null,"DisplayCaptcha":false,"Id":null,"UserFields":[]},"Comments":[],"Id":"6abdec6d83d2816248229f69","UserFields":[]}