[{"data":1,"prerenderedAt":1496},["Reactive",2],{"navigation":3,"aAII9Cz3yR":204,"tags-Vue.js":397},[4,192,200],{"title":5,"_path":6,"children":7,"icon":191},"Blog","/posts",[8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,77,80,83,86,89,92,95,98,101,104,107,110,113,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,167,170,173,176,179,182,185,188],{"title":9,"_path":10},"Testing your API with REST Client","/posts/testing-your-api-with-rest-client",{"title":12,"_path":13},"HTML templating in Xamarin","/posts/html-templating-in-xamarin",{"title":15,"_path":16},"Goodbye Azure Portal, Welcome Azure CLI","/posts/welcome-azure-cli",{"title":18,"_path":19},"Coming across Gitpod","/posts/gitpod",{"title":21,"_path":22},"Handle token retrieval while querying an API","/posts/delegating-handler",{"title":24,"_path":25},"Clean up your local git branches.","/posts/cleaning-git-branches",{"title":27,"_path":28},"Automate configuration of Teams Tab SSO with PowerShell.","/posts/teams-sso-powershell",{"title":30,"_path":31},"How to do a technology watch? - Part 1","/posts/technology-watch-part1",{"title":33,"_path":34},"How to do a technology watch? - Part 2","/posts/technology-watch-part2",{"title":36,"_path":37},"You almost no longer need Key Vault references for Azure Functions.","/posts/azure-functions-custom-configuration",{"title":39,"_path":40},"How to do a technology watch? - Part 3","/posts/technology-watch-part3",{"title":42,"_path":43},"Forget DevOps, the future is already here!","/posts/devops-future",{"title":45,"_path":46},"Week 9, 2021 - Tips I learned this week","/posts/w09-2021-tips-learned-this-week",{"title":48,"_path":49},"Week 12, 2021 - Tips I learned this week","/posts/w12-2021-tips-learned-this-week",{"title":51,"_path":52},"Week 14, 2021 - Tips I learned this week","/posts/w14-2021-tips-learned-this-week",{"title":54,"_path":55},"Once upon a time in .NET","/posts/once-upon-a-time-in-dotnet",{"title":57,"_path":58},"Install your applications with winget","/posts/winget-import",{"title":60,"_path":61},"Customize your applications when installing them with winget","/posts/winget-override",{"title":63,"_path":64},"Week 22, 2021 - Tips I learned this week","/posts/w22-2021-tips-learned-this-week",{"title":66,"_path":67},"How to connect to an Azure SQL Database from C# using Azure AD","/posts/sqlclient-active-directory-authent",{"title":69,"_path":70},"Producing packages for Windows Package Manager","/posts/wingetcreate",{"title":72,"_path":73},"4 tips about GitHub Actions environment variables and contexts","/posts/github-actions-var-and-context",{"title":75,"_path":76},"AzureWebJobsStorage, the secret you don't need in your Function App.","/posts/azure-functions-without-azurewebjobsstorage",{"title":78,"_path":79},"ASP.NET Core - Lost in configuration","/posts/lost-in-configuration",{"title":81,"_path":82},"Week 39, 2021 - Tips I learned this week","/posts/w39-2021-tips-learned-this-week",{"title":84,"_path":85},"Week 41, 2021 - Tips I learned this week","/posts/w41-2021-tips-learned-this-week",{"title":87,"_path":88},"Migrating and open-sourcing my blog","/posts/migrating-blog",{"title":90,"_path":91},"Week 45, 2021 - Tips I learned this week","/posts/w45-2021-tips-learned-this-week",{"title":93,"_path":94},"Organize your GitHub stars with Astral","/posts/astral",{"title":96,"_path":97},"Pulumi with an Azure Blob Storage backend","/posts/pulumi-azure-backend",{"title":99,"_path":100},"IaC Hot Reload with Pulumi Watch","/posts/pulumi-watch",{"title":102,"_path":103},"Week 2, 2022 - Tips I learned this week","/posts/w02-2022-tips-learned-this-week",{"title":105,"_path":106},"Week 3, 2022 - Tips I learned this week","/posts/w03-2022-tips-learned-this-week",{"title":108,"_path":109},"Week 5, 2022 - Tips I learned this week","/posts/w05-2022-tips-learned-this-week",{"title":111,"_path":112},"How to provision an Azure SQL Database with Active Directory authentication","/posts/sqldatabase-active-directory-authent",{"title":114,"_path":115},"Why will I choose Pulumi over Terraform for my next project?","/posts/pulumi-vs-terraform",{"title":117,"_path":118},"Week 19, 2022 - Tips I learned this week","/posts/w19-2022-tips-learned-this-week",{"title":120,"_path":121},"Week 20, 2022 - Tips I learned this week","/posts/w20-2022-tips-learned-this-week",{"title":123,"_path":124},"Keeping secrets secure when using API Clients","/posts/http-clients-secrets",{"title":126,"_path":127},"What made me want to be a developer?","/posts/be-a-developer",{"title":129,"_path":130},"What can we do when stuck with a programming problem?","/posts/get-unstuck",{"title":132,"_path":133},"How did I automate the setup of my developer Windows laptop?","/posts/automate-developer-machine",{"title":135,"_path":136},"Discussion about API clients","/posts/http-clients",{"title":138,"_path":139},"Week 46, 2022 - Tips I learned this week","/posts/w46-2022-tips-learned-this-week",{"title":141,"_path":142},"When Pulumi met Nuke: a .NET love story","/posts/when-pulumi-met-nuke",{"title":144,"_path":145},"A year of learning and sharing - Dev Retro 2022","/posts/2022-retro",{"title":147,"_path":148},"Perform Dynamic Execution of an npm Package","/posts/pnpm-dlx",{"title":150,"_path":151},"Manage multiple Node.js versions","/posts/pnpm-env",{"title":153,"_path":154},"Introducing the Vue.js CI/CD series","/posts/vuecicd-introduction",{"title":156,"_path":157},"Execute commands using your project dependencies","/posts/pnpm-exec",{"title":159,"_path":160},"Vue.js CI/CD: Continuous Integration","/posts/vuecicd-ci",{"title":162,"_path":163},"Who is using pnpm?","/posts/pnpm-who-is-using",{"title":165,"_path":166},"Create an Azure-Ready GitHub Repository using Pulumi","/posts/azure-ready-github-repository",{"title":168,"_path":169},"Deploying to Azure from Azure DevOps without secrets","/posts/ado-workload-identity-federation",{"title":171,"_path":172},"Effortlessly Configure GitHub Repositories for Azure Deployment via OIDC","/posts/scripting-azure-ready-github-repository",{"title":174,"_path":175},"Playing with the .NET 8 Web API template","/posts/playing-with-dotnet8",{"title":177,"_path":178},"Another year of sharing and learning - Dev Retro 2023","/posts/2023-retro",{"title":180,"_path":181},"Week 4, 2024 - Tips I learned this week","/posts/w04-2024-tips-learned-this-week",{"title":183,"_path":184},"Using dependency injection with Azure .NET SDK","/posts/azure-sdk-di",{"title":186,"_path":187},"Having Fun With IT Event Calendars","/posts/it-event-calendars",{"title":189,"_path":190},"Call your Azure AD B2C protected API with authenticated HTTP requests from your JetBrains IDE","/posts/http-clients-oauth2","i-heroicons-newspaper",{"title":193,"_path":194,"children":195,"icon":199},"Goodies","/goodies",[196],{"title":197,"_path":198},"My Git Cheat Sheet","/goodies/gitcheatsheet","i-heroicons-gift-solid",{"title":201,"_path":202,"icon":203},"About","/about","i-heroicons-user-circle-solid",[205,207,209,211,214,217,220,223,226,229,231,234,237,240,242,244,247,250,253,255,258,261,264,267,270,273,276,279,282,285,287,289,292,294,297,300,303,305,308,310,313,316,319,322,325,327,329,332,335,338,341,344,347,350,353,356,359,361,363,366,369,372,375,377,380,383,385,388,391,394],[206,206],"tooling",[208,208],"vscode",[210,210],"rest",[212,213],"http","HTTP",[215,216],"razor","Razor",[218,219],"xamarin","Xamarin",[221,222],"templating","Templating",[224,225],"azure-cli","Azure CLI",[227,228],"azure","Azure",[230,230],"shell",[232,233],"github","GitHub",[235,236],"asp-net-core","ASP.NET Core",[238,239],"net",".NET",[241,241],"git",[243,243],"nushell",[245,246],"microsoft-teams","Microsoft Teams",[248,249],"powershell","PowerShell",[251,252],"azure-active-directory","Azure Active Directory",[254,254],"learning",[256,257],"azure-functions","Azure Functions",[259,260],"azure-key-vault","Azure Key Vault",[262,263],"configuration","Configuration",[265,266],"devops","DevOps",[268,269],"it","IT",[271,272],"tips-learned-this-week","tips learned this week",[274,275],"windows-terminal","Windows Terminal",[277,278],"azure-pipelines","Azure Pipelines",[280,281],"application-insights","Application Insights",[283,284],"azure-iot","Azure IoT",[286,286],"records",[288,288],"refit",[290,291],"development-box-setup","development box setup",[293,293],"winget",[295,296],"package-manager","package manager",[298,299],"azure-sql-database","Azure SQL Database",[301,302],"azure-sdk","Azure SDK",[304,304],"wingetcreate",[306,307],"github-actions","GitHub Actions",[309,309],"jq",[311,312],"pulumi","Pulumi",[314,315],"iac","IaC",[317,318],"azure-storage","Azure Storage",[320,321],"azure-signalr","Azure SignalR",[323,324],"visio","Visio",[326,326],"csharp",[328,328],"jest",[330,331],"statiq","Statiq",[333,334],"open-source","open source",[336,337],"visual-studio","Visual Studio",[339,340],"vue-js","Vue.js",[342,343],"azure-devops","Azure DevOps",[345,346],"vite","Vite",[348,349],"code-analysis","Code analysis",[351,352],"diagram","Diagram",[354,355],"terraform","Terraform",[357,358],"typescript","TypeScript",[360,360],"thoughts",[362,362],"pnpm",[364,365],"nuke","Nuke",[367,368],"pipelines","Pipelines",[370,371],"cicd","CI/CD",[373,374],"openid-connect","OpenID Connect",[376,376],"security",[378,379],"github-cli","GitHub CLI",[381,382],"microsoft-entra-id","Microsoft Entra ID",[384,384],"advent",[386,387],"finops","FinOps",[389,390],"anglesharp","AngleSharp",[392,393],"oauth2","OAuth2",[395,396],"azure-ad-b2c","Azure AD B2C",[398,753,1000,1225],{"_path":160,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":159,"description":402,"date":403,"image":404,"badge":406,"tags":407,"canonical":408,"body":409,"_type":748,"_id":749,"_source":750,"_file":751,"_extension":752},"posts",false,"","Post about continuous integration with Vue.js.","2023-06-22T00:00:00.000Z",{"src":405},"/images/vue-cicd.webp",{"label":266},[340,371,266],"https://bordeauxcoders.com/vuejs-cicd-continuous-integration",{"type":410,"children":411,"toc":741},"root",[412,421,427,432,437,442,462,468,473,478,508,518,530,535,540,546,568,577,589,624,634,675,698,703,709,721],{"type":413,"tag":414,"props":415,"children":417},"element","h2",{"id":416},"why-are-we-talking-about-ci-in-the-first-place",[418],{"type":419,"value":420},"text","Why are we talking about CI in the first place?",{"type":413,"tag":422,"props":423,"children":424},"p",{},[425],{"type":419,"value":426},"When working on a project, you typically focus on a specific feature at a time, making changes on a dedicated branch for that feature. When it's time for you to integrate these modifications into the project's code base, the code base has likely evolved since you began working on your feature, as other team members have also pushed their work. That's why your code changes may introduce errors in the application you are developing.",{"type":413,"tag":422,"props":428,"children":429},{},[430],{"type":419,"value":431},"Regardless of that, while implementing your feature you might have broken some tests, added a security vulnerability, reduced code quality, or simply not adhered to all code conventions used by your team. Even if your colleagues review the code of your Pull Request, they can miss some of these issues. Nonetheless, it would be more efficient for such errors to be detected automatically, enabling people to concentrate their feedback on other aspects.",{"type":413,"tag":422,"props":433,"children":434},{},[435],{"type":419,"value":436},"Continuous Integration enables us to do precisely that: automatically identify potential issues and make the integration of new changes in a project's code base less error-prone.",{"type":413,"tag":422,"props":438,"children":439},{},[440],{"type":419,"value":441},"According to Microsoft:",{"type":413,"tag":443,"props":444,"children":445},"blockquote",{},[446],{"type":413,"tag":422,"props":447,"children":448},{},[449,451,460],{"type":419,"value":450},"Continuous integration (CI) is the process of automatically building and testing code every time a team member commits code changes to ",{"type":413,"tag":452,"props":453,"children":457},"a",{"href":454,"rel":455},"https://learn.microsoft.com/en-us/devops/develop/git/what-is-version-control",[456],"nofollow",[458],{"type":419,"value":459},"version control",{"type":419,"value":461},".",{"type":413,"tag":414,"props":463,"children":465},{"id":464},"what-are-the-steps-involved-in-a-ci-pipeline",[466],{"type":419,"value":467},"What are the steps involved in a CI pipeline?",{"type":413,"tag":422,"props":469,"children":470},{},[471],{"type":419,"value":472},"We often hear discussions about the \"Build pipeline\" and the \"Release pipeline\" as if building the application was the only task performed in a continuous integration pipeline. However, this is far from the truth; the \"Build\" is an important step, but not the only one.",{"type":413,"tag":422,"props":474,"children":475},{},[476],{"type":419,"value":477},"Up until now, we have talked a lot about continuous integration for projects in general but nothing specific for Vue.js. Why is that? Because the steps for continuous integration of a Vue.js project are the same as for any other project:",{"type":413,"tag":479,"props":480,"children":481},"ul",{},[482,488,493,498,503],{"type":413,"tag":483,"props":484,"children":485},"li",{},[486],{"type":419,"value":487},"Install dependencies",{"type":413,"tag":483,"props":489,"children":490},{},[491],{"type":419,"value":492},"Build the application",{"type":413,"tag":483,"props":494,"children":495},{},[496],{"type":419,"value":497},"Perform code quality static analysis",{"type":413,"tag":483,"props":499,"children":500},{},[501],{"type":419,"value":502},"Perform security analysis",{"type":413,"tag":483,"props":504,"children":505},{},[506],{"type":419,"value":507},"Run tests",{"type":413,"tag":509,"props":510,"children":512},"callout",{"icon":511},"i-heroicons-chat-bubble-left-20-solid",[513],{"type":413,"tag":422,"props":514,"children":515},{},[516],{"type":419,"value":517},"It's good to know that, as part of the build step, an executable artifact is often generated, and then used (in the same pipeline or a CD pipeline) to deploy the application in an environment.",{"type":413,"tag":422,"props":519,"children":520},{},[521],{"type":413,"tag":522,"props":523,"children":529},"img",{"alt":524,"className":525,"src":528},"Diagram of a CI/CD pipeline.",[526,527],"rounded-lg","mx-auto","/posts/images/vuecicd_ci_pipeline.png",[],{"type":413,"tag":422,"props":531,"children":532},{},[533],{"type":419,"value":534},"Depending on your project, preferences, and available services, your continuous integration process may vary, but it should include these steps, regardless of the tools you use within them.",{"type":413,"tag":422,"props":536,"children":537},{},[538],{"type":419,"value":539},"There might be additional steps in your Continuous Integration pipeline, but the ones mentioned are the primary ones. Moreover, security is not an optional step; it should be an integral part of your continuous integration.",{"type":413,"tag":414,"props":541,"children":543},{"id":542},"leveraging-packagejson-for-your-ci-setup",[544],{"type":419,"value":545},"Leveraging package.json for your CI setup",{"type":413,"tag":422,"props":547,"children":548},{},[549,551,558,560,566],{"type":419,"value":550},"When you create a Vue.js project using ",{"type":413,"tag":552,"props":553,"children":555},"code",{"className":554},[],[556],{"type":419,"value":557},"create-vue",{"type":419,"value":559},", the generated ",{"type":413,"tag":552,"props":561,"children":563},{"className":562},[],[564],{"type":419,"value":565},"package.json",{"type":419,"value":567}," file will contain several npm scripts:",{"type":413,"tag":422,"props":569,"children":570},{},[571],{"type":413,"tag":522,"props":572,"children":576},{"alt":573,"className":574,"src":575},"Screenshot of the npm scripts section of a package.json file.",[526,527],"/posts/images/vuecicd_ci_packagejson_0.png",[],{"type":413,"tag":422,"props":578,"children":579},{},[580,582,587],{"type":419,"value":581},"You can observe that some of these scripts precisely correspond to the necessary steps for the continuous integration pipeline, such as build and unit tests. We will discuss each of them in future articles but the npm scripts in the default ",{"type":413,"tag":552,"props":583,"children":585},{"className":584},[],[586],{"type":419,"value":557},{"type":419,"value":588}," template are definitively a good starting point to set up your CI.",{"type":413,"tag":422,"props":590,"children":591},{},[592,594,600,602,607,609,615,617,622],{"type":419,"value":593},"You can see that packages used in the npm scripts are specified in the ",{"type":413,"tag":552,"props":595,"children":597},{"className":596},[],[598],{"type":419,"value":599},"devDependencies",{"type":419,"value":601}," section of the ",{"type":413,"tag":552,"props":603,"children":605},{"className":604},[],[606],{"type":419,"value":565},{"type":419,"value":608}," file. That means these packages will be available to use locally or in a CI server after executing the ",{"type":413,"tag":552,"props":610,"children":612},{"className":611},[],[613],{"type":419,"value":614},"pnpm install",{"type":419,"value":616}," command. As part of the CI, other packages may also be needed, so you should include them in the ",{"type":413,"tag":552,"props":618,"children":620},{"className":619},[],[621],{"type":419,"value":599},{"type":419,"value":623}," section as well.",{"type":413,"tag":422,"props":625,"children":626},{},[627],{"type":413,"tag":522,"props":628,"children":633},{"alt":629,"className":630,"src":631,"width":632},"Screenshot of the devdependencies section of a package.json file.",[526,527],"/posts/images/vuecicd_ci_packagejson_1.png",1000,[],{"type":413,"tag":422,"props":635,"children":636},{},[637,639,644,646,657,659,665,667,673],{"type":419,"value":638},"In your CI pipeline, I think it's a good idea to directly execute the npm scripts of the ",{"type":413,"tag":552,"props":640,"children":642},{"className":641},[],[643],{"type":419,"value":565},{"type":419,"value":645}," file rather than specifying the packages you want to run along with their corresponding flags and parameters. You can accomplish this by using the ",{"type":413,"tag":452,"props":647,"children":650},{"href":648,"rel":649},"https://pnpm.io/fr/cli/run",[456],[651],{"type":413,"tag":552,"props":652,"children":654},{"className":653},[],[655],{"type":419,"value":656},"pnpm run",{"type":419,"value":658}," command like so: ",{"type":413,"tag":552,"props":660,"children":662},{"className":661},[],[663],{"type":419,"value":664},"pnpm run build",{"type":419,"value":666}," or ",{"type":413,"tag":552,"props":668,"children":670},{"className":669},[],[671],{"type":419,"value":672},"pnpm build",{"type":419,"value":674}," (all npm scripts are aliased by pnpm by default). Of course, you'll need to add any missing npm scripts required for your CI. There are several benefits to this approach:",{"type":413,"tag":479,"props":676,"children":677},{},[678,683,688,693],{"type":413,"tag":483,"props":679,"children":680},{},[681],{"type":419,"value":682},"It simplifies the CI pipeline and makes it easier to read",{"type":413,"tag":483,"props":684,"children":685},{},[686],{"type":419,"value":687},"you won't have to modify your pipeline when you change something in an npm script (whether it's the package you use or just a parameter)",{"type":413,"tag":483,"props":689,"children":690},{},[691],{"type":419,"value":692},"the steps in your CI pipeline will be more consistent across projects (including both Vue.js and non-Vue.js projects) if you always use the same npm script names",{"type":413,"tag":483,"props":694,"children":695},{},[696],{"type":419,"value":697},"the same commands will be executed with the same parameters, whether locally or on a CI server",{"type":413,"tag":422,"props":699,"children":700},{},[701],{"type":419,"value":702},"It's important to note that you should not wait for a CI pipeline execution to detect issues in your code. The sooner you identify and resolve problems, the better. Before pushing your changes, you should run the npm scripts that test your code and perform static analysis on it.",{"type":413,"tag":414,"props":704,"children":706},{"id":705},"wrapping-it-up",[707],{"type":419,"value":708},"Wrapping it up",{"type":413,"tag":422,"props":710,"children":711},{},[712,714,719],{"type":419,"value":713},"Setting up a Continuous Integration pipeline for your Vue.js project is essential for preventing issues, maintaining code quality, ensuring security, and streamlining the development process. By leveraging the npm scripts of the ",{"type":413,"tag":552,"props":715,"children":717},{"className":716},[],[718],{"type":419,"value":565},{"type":419,"value":720}," file you can simplify your CI pipeline and ensure consistency both locally and on the CI server, as well as across your projects.",{"type":413,"tag":422,"props":722,"children":723},{},[724,726,732,733,739],{"type":419,"value":725},"Future articles in this series will delve into the details of various stages of a continuous integration pipeline (such as using ",{"type":413,"tag":552,"props":727,"children":729},{"className":728},[],[730],{"type":419,"value":731},"vue-tsc",{"type":419,"value":666},{"type":413,"tag":552,"props":734,"children":736},{"className":735},[],[737],{"type":419,"value":738},"eslint",{"type":419,"value":740}," for static analysis) and their implementation in GitLab CI or GitHub Actions pipelines.",{"title":401,"searchDepth":742,"depth":742,"links":743},2,[744,745,746,747],{"id":416,"depth":742,"text":420},{"id":464,"depth":742,"text":467},{"id":542,"depth":742,"text":545},{"id":705,"depth":742,"text":708},"markdown","content:1.posts:51.vuecicd-ci.md","content","1.posts/51.vuecicd-ci.md","md",{"_path":154,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":153,"description":754,"date":755,"image":756,"badge":757,"tags":758,"canonical":759,"body":760,"_type":748,"_id":998,"_source":750,"_file":999,"_extension":752},"This is the first article of the Vue.js CI/CD series. It will be the opportunity to explain the purpose of the series and the topics we plan to cover.","2023-06-01T00:00:00.000Z",{"src":405},{"label":266},[340,371,266],"https://bordeauxcoders.com/introducing-the-vuejs-cicd-series",{"type":410,"children":761,"toc":989},[762,766,772,777,782,788,793,825,830,837,842,847,853,858,876,882,887,904,912,925,943,960,984],{"type":413,"tag":422,"props":763,"children":764},{},[765],{"type":419,"value":754},{"type":413,"tag":414,"props":767,"children":769},{"id":768},"why-this-series",[770],{"type":419,"value":771},"Why this series?",{"type":413,"tag":422,"props":773,"children":774},{},[775],{"type":419,"value":776},"We delved deeply into CI/CD for Vue.js when preparing a DevOps practices course for students in engineering school. The course wasn't directly related to Vue.js; however, we chose to use a Vue.js application for hands-on exercises focused on implementing CI/CD pipelines. Through this process, we gained valuable insights that we now wish to share.",{"type":413,"tag":422,"props":778,"children":779},{},[780],{"type":419,"value":781},"While there are numerous blog posts on Vue.js, not many articles specifically address setting up CI/CD pipelines for Vue.js projects. Yet, having proper continuous integration and automating deployments are two aspects that should not be neglected in a project. That's the main reason why we decided to write this Vue.js CI/CD series.",{"type":413,"tag":414,"props":783,"children":785},{"id":784},"what-are-we-going-to-talk-about",[786],{"type":419,"value":787},"What are we going to talk about?",{"type":413,"tag":422,"props":789,"children":790},{},[791],{"type":419,"value":792},"As you can expect, we will cover the usual topics:",{"type":413,"tag":479,"props":794,"children":795},{},[796,801,806,811,816,820],{"type":413,"tag":483,"props":797,"children":798},{},[799],{"type":419,"value":800},"package management",{"type":413,"tag":483,"props":802,"children":803},{},[804],{"type":419,"value":805},"build & artifacts",{"type":413,"tag":483,"props":807,"children":808},{},[809],{"type":419,"value":810},"static analysis",{"type":413,"tag":483,"props":812,"children":813},{},[814],{"type":419,"value":815},"testing",{"type":413,"tag":483,"props":817,"children":818},{},[819],{"type":419,"value":376},{"type":413,"tag":483,"props":821,"children":822},{},[823],{"type":419,"value":824},"deployment",{"type":413,"tag":422,"props":826,"children":827},{},[828],{"type":419,"value":829},"Examples will be shown using different CI/CD platforms and cloud services.",{"type":413,"tag":831,"props":832,"children":834},"h3",{"id":833},"cicd-platforms",[835],{"type":419,"value":836},"CI/CD platforms",{"type":413,"tag":422,"props":838,"children":839},{},[840],{"type":419,"value":841},"We can't cover all the CI/CD platforms so we will focus on GitHub Actions and GitLab CI.",{"type":413,"tag":422,"props":843,"children":844},{},[845],{"type":419,"value":846},"Even though each platform has its unique features, the majority of the concepts we will discuss can be applied to other platforms as well. So, don't stop reading the series just because you are using a different platform 😉.",{"type":413,"tag":831,"props":848,"children":850},{"id":849},"cloud-services",[851],{"type":419,"value":852},"Cloud services",{"type":413,"tag":422,"props":854,"children":855},{},[856],{"type":419,"value":857},"There are numerous hosting options for a Vue.js application, and we will demonstrate how to deploy an application on at least the following platforms:",{"type":413,"tag":479,"props":859,"children":860},{},[861,866,871],{"type":413,"tag":483,"props":862,"children":863},{},[864],{"type":419,"value":865},"Azure Static Web App",{"type":413,"tag":483,"props":867,"children":868},{},[869],{"type":419,"value":870},"Vercel",{"type":413,"tag":483,"props":872,"children":873},{},[874],{"type":419,"value":875},"Netlify",{"type":413,"tag":414,"props":877,"children":879},{"id":878},"which-sample-application-will-we-be-using",[880],{"type":419,"value":881},"Which sample application will we be using?",{"type":413,"tag":422,"props":883,"children":884},{},[885],{"type":419,"value":886},"This series aims to discuss CI/CD for Vue.js applications so that anyone can learn how to set up a CI/CD pipeline for their Vue.js project. That's why we will use the sample code from the basic application generated when creating a new Vue.js project.",{"type":413,"tag":422,"props":888,"children":889},{},[890,892,902],{"type":419,"value":891},"And to be clear, when you start a new Vue.js project you don't want to use the Vue CLI because it is in maintenance mode. Instead, you should use ",{"type":413,"tag":452,"props":893,"children":896},{"href":894,"rel":895},"https://github.com/vuejs/create-vue",[456],[897],{"type":413,"tag":552,"props":898,"children":900},{"className":899},[],[901],{"type":419,"value":557},{"type":419,"value":903}," which is based on Vite and is the recommended way of scaffolding a Vue.js project.",{"type":413,"tag":509,"props":905,"children":906},{"icon":511},[907],{"type":413,"tag":422,"props":908,"children":909},{},[910],{"type":419,"value":911},"I think it's important to mention it because I still see new blog posts talking about creating new projects using Vue CLI.",{"type":413,"tag":422,"props":913,"children":914},{},[915,917,923],{"type":419,"value":916},"So nothing specific in the code of the application we will build and deploy, just the basic things you get when you run the ",{"type":413,"tag":552,"props":918,"children":920},{"className":919},[],[921],{"type":419,"value":922},"pnpm create vue@latest",{"type":419,"value":924}," command with:",{"type":413,"tag":479,"props":926,"children":927},{},[928,933,938],{"type":413,"tag":483,"props":929,"children":930},{},[931],{"type":419,"value":932},"TypeScript enabled ➡️ it's 2023, I don't see any valid reason why to choose Vanilla JS instead of TypeScript so if you are not using TypeScript you probably should",{"type":413,"tag":483,"props":934,"children":935},{},[936],{"type":419,"value":937},"Vitest enabled ➡️ the vite-native unit test framework you want to use to test your code",{"type":413,"tag":483,"props":939,"children":940},{},[941],{"type":419,"value":942},"ESLint enabled ➡️ because static analysis should be part of your Continuous Integration pipeline",{"type":413,"tag":422,"props":944,"children":945},{},[946,948,958],{"type":419,"value":947},"The last thing to mention: we will use the latest version of ",{"type":413,"tag":452,"props":949,"children":952},{"href":950,"rel":951},"https://pnpm.io/",[456],[953],{"type":413,"tag":552,"props":954,"children":956},{"className":955},[],[957],{"type":419,"value":362},{"type":419,"value":959}," to manage dependencies. Our preferred package manager is pnpm for various reasons, but the primary one is its remarkable speed!",{"type":413,"tag":509,"props":961,"children":962},{"icon":511},[963],{"type":413,"tag":422,"props":964,"children":965},{},[966,968,974,976,983],{"type":419,"value":967},"You can check the ",{"type":413,"tag":452,"props":969,"children":971},{"href":950,"rel":970},[456],[972],{"type":419,"value":973},"pnpm website",{"type":419,"value":975}," to read more about pnpm or have a look at our ",{"type":413,"tag":452,"props":977,"children":980},{"href":978,"rel":979},"https://bordeauxcoders.com/series/pnpm-101",[456],[981],{"type":419,"value":982},"pnpm 101 series",{"type":419,"value":461},{"type":413,"tag":422,"props":985,"children":986},{},[987],{"type":419,"value":988},"We hope you will have a great time learning about CI/CD for Vue.js application. See you in the next article.",{"title":401,"searchDepth":742,"depth":742,"links":990},[991,992,997],{"id":768,"depth":742,"text":771},{"id":784,"depth":742,"text":787,"children":993},[994,996],{"id":833,"depth":995,"text":836},3,{"id":849,"depth":995,"text":852},{"id":878,"depth":742,"text":881},"content:1.posts:49.vuecicd-introduction.md","1.posts/49.vuecicd-introduction.md",{"_path":118,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":117,"description":1001,"lead":1001,"date":1002,"image":1003,"badge":1005,"tags":1007,"body":1008,"_type":748,"_id":1223,"_source":750,"_file":1224,"_extension":752},"Git commands in vscode, a nice tool for Vue developers and a must-have Visual Studio extension.","2022-05-14T00:00:00.000Z",{"src":1004},"/images/surface_1.jpg",{"label":1006},"Tips",[272,208,241,340,337,206],{"type":410,"children":1009,"toc":1218},[1010,1016,1048,1057,1062,1071,1083,1089,1138,1147,1161,1170,1176,1190,1199,1204,1213],{"type":413,"tag":414,"props":1011,"children":1013},{"id":1012},"git-tip-of-the-week",[1014],{"type":419,"value":1015},"Git tip of the week",{"type":413,"tag":422,"props":1017,"children":1018},{},[1019,1021,1028,1030,1037,1039,1046],{"type":419,"value":1020},"If you have read my ",{"type":413,"tag":452,"props":1022,"children":1025},{"href":1023,"rel":1024},"https://www.techwatching.dev/gitcheatsheet",[456],[1026],{"type":419,"value":1027},"git cheat sheet",{"type":419,"value":1029},", you know that I am a big fan of the ",{"type":413,"tag":452,"props":1031,"children":1034},{"href":1032,"rel":1033},"https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens",[456],[1035],{"type":419,"value":1036},"GitLens",{"type":419,"value":1038}," vscode extension. I have been using it for a while now but just discovered recently that there is a ",{"type":413,"tag":452,"props":1040,"children":1043},{"href":1041,"rel":1042},"https://github.com/gitkraken/vscode-gitlens#git-command-palette-",[456],[1044],{"type":419,"value":1045},"Git Command Palette",{"type":419,"value":1047}," that gives access to most common Git commands.",{"type":413,"tag":422,"props":1049,"children":1050},{},[1051],{"type":413,"tag":522,"props":1052,"children":1056},{"alt":1053,"className":1054,"src":1055,"width":632},"GitLens Command Palette in vscode",[526,527],"/posts/images/w192022tips_gitlens_1.png",[],{"type":413,"tag":422,"props":1058,"children":1059},{},[1060],{"type":419,"value":1061},"Usually, I prefer typing the git commands rather than using a visual tool. This way, I know exactly what I am doing (no magic commands done by a tool behind the scene), and I improve my knowledge of git. However, I think that with Git Command Palette, I get the best of both worlds. The UI helps me to use the git command I need without having to type everything and remember the exact syntax of the command. Yet, this is not a UI with buttons that hide from me the git commands being run. I am still aware of the exact git commands I am using and how.",{"type":413,"tag":422,"props":1063,"children":1064},{},[1065],{"type":413,"tag":522,"props":1066,"children":1070},{"alt":1067,"className":1068,"src":1069,"width":632},"Doing a Git fetch in GitLens Command Palette.",[526,527],"/posts/images/w192022tips_gitlens_2.png",[],{"type":413,"tag":422,"props":1072,"children":1073},{},[1074,1076,1082],{"type":419,"value":1075},"On Windows, the default shortcut to use the Git Command Palette is ",{"type":413,"tag":552,"props":1077,"children":1079},{"className":1078},[],[1080],{"type":419,"value":1081},"Ctrl + Shift + G : ",{"type":419,"value":461},{"type":413,"tag":414,"props":1084,"children":1086},{"id":1085},"tool-of-the-week-vue-telescope",[1087],{"type":419,"value":1088},"Tool of the week: Vue Telescope",{"type":413,"tag":422,"props":1090,"children":1091},{},[1092,1094,1101,1103,1110,1112,1119,1121,1128,1130,1136],{"type":419,"value":1093},"If you are a Vue developer and don't know this tool yet, this is going to make your day! When browsing a website, you are probably wondering if it has been made with Vue.js and if so what is the technology stack behind it. Personally, I find it very interesting to know which frameworks, libraries, or plugins have been used to create a website in Vue. And that's what ",{"type":413,"tag":452,"props":1095,"children":1098},{"href":1096,"rel":1097},"https://vuetelescope.com/",[456],[1099],{"type":419,"value":1100},"Vue Telescope",{"type":419,"value":1102}," is about. It's an open source tool made by ",{"type":413,"tag":452,"props":1104,"children":1107},{"href":1105,"rel":1106},"https://nuxtlabs.com/",[456],[1108],{"type":419,"value":1109},"NuxtLabs",{"type":419,"value":1111}," (the team behind the ",{"type":413,"tag":452,"props":1113,"children":1116},{"href":1114,"rel":1115},"https://nuxtjs.org/",[456],[1117],{"type":419,"value":1118},"Nuxt",{"type":419,"value":1120}," framework) that detects the Vue technologies used in a website. It can be used from a browser ",{"type":413,"tag":452,"props":1122,"children":1125},{"href":1123,"rel":1124},"https://chrome.google.com/webstore/detail/vue-telescope/neaebjphlfplgdhedjdhcnpjkndddbpd",[456],[1126],{"type":419,"value":1127},"extension",{"type":419,"value":1129}," or from Vue Telescope's ",{"type":413,"tag":452,"props":1131,"children":1133},{"href":1096,"rel":1132},[456],[1134],{"type":419,"value":1135},"website",{"type":419,"value":1137}," to search a analyze a specific website.",{"type":413,"tag":422,"props":1139,"children":1140},{},[1141],{"type":413,"tag":522,"props":1142,"children":1146},{"alt":1143,"className":1144,"src":1145,"width":632},"Vue Telescope extension showing Vue Telescope stack on its website.",[526,527],"/posts/images/w192022tips_vuetelescope_1.png",[],{"type":413,"tag":422,"props":1148,"children":1149},{},[1150,1152,1159],{"type":419,"value":1151},"You can explore the Vue.js websites already scanned by VueTelescope ",{"type":413,"tag":452,"props":1153,"children":1156},{"href":1154,"rel":1155},"https://vuetelescope.com/explore",[456],[1157],{"type":419,"value":1158},"here",{"type":419,"value":1160}," and filter on the frameworks, UI Frameworks you are interested in.",{"type":413,"tag":422,"props":1162,"children":1163},{},[1164],{"type":413,"tag":522,"props":1165,"children":1169},{"alt":1166,"className":1167,"src":1168,"width":632},"Vue Telescope search.",[526,527],"/posts/images/w192022tips_vuetelescope_2.png",[],{"type":413,"tag":414,"props":1171,"children":1173},{"id":1172},"the-visual-studio-extension-you-should-try-add-new-file",[1174],{"type":419,"value":1175},"The Visual Studio extension you should try: Add New File",{"type":413,"tag":422,"props":1177,"children":1178},{},[1179,1181,1188],{"type":419,"value":1180},"Sometimes the simplest IDE extensions are the best. That's the case for the ",{"type":413,"tag":452,"props":1182,"children":1185},{"href":1183,"rel":1184},"https://marketplace.visualstudio.com/items?itemName=MadsKristensen.AddNewFile64",[456],[1186],{"type":419,"value":1187},"\"Add New\"",{"type":419,"value":1189}," Visual Studio extension which allows you to quickly create a new file by hitting \"Shift+F2\" and writing the name of the file with its extension. Nothing fancy, but it saves you a lot of time compared to adding a new file using the default dialog.",{"type":413,"tag":422,"props":1191,"children":1192},{},[1193],{"type":413,"tag":522,"props":1194,"children":1198},{"alt":1195,"className":1196,"src":1197,"width":632},"Website of Add New File Visual Studio extension.",[526,527],"/posts/images/w192022tips_addnewfile_1.png",[],{"type":413,"tag":422,"props":1200,"children":1201},{},[1202],{"type":419,"value":1203},"As you can see you can even create the missing folders where the file is placed.",{"type":413,"tag":422,"props":1205,"children":1206},{},[1207],{"type":413,"tag":522,"props":1208,"children":1212},{"alt":1209,"className":1210,"src":1211,"width":632},"Usage of Add New File in Visual Studio.",[526,527],"/posts/images/w192022tips_addnewfile.gif",[],{"type":413,"tag":422,"props":1214,"children":1215},{},[1216],{"type":419,"value":1217},"And that's it for this week, happy learning!",{"title":401,"searchDepth":742,"depth":742,"links":1219},[1220,1221,1222],{"id":1012,"depth":742,"text":1015},{"id":1085,"depth":742,"text":1088},{"id":1172,"depth":742,"text":1175},"content:1.posts:37.w19-2022-tips-learned-this-week.md","1.posts/37.w19-2022-tips-learned-this-week.md",{"_path":91,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":90,"description":1226,"lead":1227,"date":1228,"image":1229,"badge":1230,"tags":1231,"body":1232,"_type":748,"_id":1494,"_source":750,"_file":1495,"_extension":752},"Vue Devtools, Visual Studio themes, Git tips, and .NET Conf replays.","A bit of tooling and a bit of git.","2021-11-14T00:00:00.000Z",{"src":1004},{"label":1006},[272,337,340,241],{"type":410,"children":1233,"toc":1486},[1234,1246,1258,1289,1298,1304,1327,1350,1359,1365,1370,1375,1381,1409,1437,1454,1460,1473,1482],{"type":413,"tag":414,"props":1235,"children":1237},{"id":1236},"vue-devtools-a-must-have-browser-extension-when-using-vuejs",[1238,1244],{"type":413,"tag":552,"props":1239,"children":1241},{"className":1240},[],[1242],{"type":419,"value":1243},"Vue Devtools",{"type":419,"value":1245},", a must-have browser extension when using Vue.js",{"type":413,"tag":422,"props":1247,"children":1248},{},[1249,1251,1256],{"type":419,"value":1250},"Since a colleague showed me the ",{"type":413,"tag":552,"props":1252,"children":1254},{"className":1253},[],[1255],{"type":419,"value":1243},{"type":419,"value":1257}," extension, it has been a game-changer for me to work on Vue.js projects. It is very useful!",{"type":413,"tag":422,"props":1259,"children":1260},{},[1261,1263,1270,1272,1279,1281,1287],{"type":419,"value":1262},"I could describe to you how this extension works and what are its features but there are already very good articles that do that, like this ",{"type":413,"tag":452,"props":1264,"children":1267},{"href":1265,"rel":1266},"https://www.vuemastery.com/blog/whats-new-in-the-vue3-devtools/",[456],[1268],{"type":419,"value":1269},"one",{"type":419,"value":1271}," on Vue Mastery's blog. Check that, have a look at the ",{"type":413,"tag":452,"props":1273,"children":1276},{"href":1274,"rel":1275},"https://devtools.vuejs.org/",[456],[1277],{"type":419,"value":1278},"documentation",{"type":419,"value":1280},", install ",{"type":413,"tag":452,"props":1282,"children":1285},{"href":1283,"rel":1284},"https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg",[456],[1286],{"type":419,"value":268},{"type":419,"value":1288}," (the beta version), and try it.",{"type":413,"tag":422,"props":1290,"children":1291},{},[1292],{"type":413,"tag":522,"props":1293,"children":1297},{"alt":1294,"className":1295,"src":1296},"Vue Devtools website.",[526,527],"/posts/images/w452021tips_vue_1.png",[],{"type":413,"tag":414,"props":1299,"children":1301},{"id":1300},"cobalt2-theme-is-available-in-visual-studio-2022",[1302],{"type":419,"value":1303},"Cobalt2 theme is available in Visual Studio 2022",{"type":413,"tag":422,"props":1305,"children":1306},{},[1307,1309,1316,1318,1325],{"type":419,"value":1308},"I have used ",{"type":413,"tag":452,"props":1310,"children":1313},{"href":1311,"rel":1312},"https://marketplace.visualstudio.com/items?itemName=wesbos.theme-cobalt2",[456],[1314],{"type":419,"value":1315},"Cobalt2 theme",{"type":419,"value":1317}," for vscode for quite some time now. And this theme is now available in Visual Studio 2022, you can check ",{"type":413,"tag":452,"props":1319,"children":1322},{"href":1320,"rel":1321},"https://marketplace.visualstudio.com/items?itemName=SIBA.Cobalt2Theme",[456],[1323],{"type":419,"value":1324},"this extension",{"type":419,"value":1326}," to get it.",{"type":413,"tag":422,"props":1328,"children":1329},{},[1330,1332,1339,1341,1348],{"type":419,"value":1331},"A lot of vscode themes have been made available in Visual Studio 2022 thanks to a new tool: ",{"type":413,"tag":452,"props":1333,"children":1336},{"href":1334,"rel":1335},"https://github.com/microsoft/theme-converter-for-vs",[456],[1337],{"type":419,"value":1338},"Theme Converter for Visual Studio",{"type":419,"value":1340},". You can read more about that ",{"type":413,"tag":452,"props":1342,"children":1345},{"href":1343,"rel":1344},"https://devblogs.microsoft.com/visualstudio/custom-themes/",[456],[1346],{"type":419,"value":1347},"in this article",{"type":419,"value":1349}," from Visual Studio dev blog.",{"type":413,"tag":422,"props":1351,"children":1352},{},[1353],{"type":413,"tag":522,"props":1354,"children":1358},{"alt":1355,"className":1356,"src":1357},"Visual Studio 2022 with cobalt theme.",[526,527],"/posts/images/w452021tips_vs_1.png",[],{"type":413,"tag":414,"props":1360,"children":1362},{"id":1361},"keep-a-2nd-clone-for-reviewing-pull-requests",[1363],{"type":419,"value":1364},"Keep a 2nd clone for reviewing pull requests",{"type":413,"tag":422,"props":1366,"children":1367},{},[1368],{"type":419,"value":1369},"I think it is often interesting to checkout the branch of a pull request instead of relying only on the web view to review a PR. It allows checking more things and a better comprehension of the code. However, when you are working on a feature, you don't want to mix your current work with the pull request you are reviewing.",{"type":413,"tag":422,"props":1371,"children":1372},{},[1373],{"type":419,"value":1374},"That is why instead of stashing code changes and switching branches I prefer having on my laptop 2 clones of the same repository I am working on, with one clone dedicated to code reviews.",{"type":413,"tag":414,"props":1376,"children":1378},{"id":1377},"git-clrf",[1379],{"type":419,"value":1380},"Git CLRF",{"type":413,"tag":422,"props":1382,"children":1383},{},[1384,1386,1392,1394,1400,1402,1408],{"type":419,"value":1385},"If you are using Git on Windows, it is a good practice to set your ",{"type":413,"tag":552,"props":1387,"children":1389},{"className":1388},[],[1390],{"type":419,"value":1391},"autocrlf",{"type":419,"value":1393}," to true in your Git configuration to avoid line-ending issues (learn more about this topic in the ",{"type":413,"tag":452,"props":1395,"children":1398},{"href":1396,"rel":1397},"https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration",[456],[1399],{"type":419,"value":1278},{"type":419,"value":1401},"). You can do that with the following command ",{"type":413,"tag":552,"props":1403,"children":1405},{"className":1404},[],[1406],{"type":419,"value":1407},"git config --global core.autocrlf true",{"type":419,"value":461},{"type":413,"tag":422,"props":1410,"children":1411},{},[1412,1414,1419,1421,1427,1429,1435],{"type":419,"value":1413},"Unfortunately, maybe not all your colleagues have correctly configured ",{"type":413,"tag":552,"props":1415,"children":1417},{"className":1416},[],[1418],{"type":419,"value":1391},{"type":419,"value":1420}," on their machine. And you will probably forget to ask each newcomer to check that. So something that can be interesting (if all your team is working on Windows) is to directly enforce this setting on your repository by pushing a ",{"type":413,"tag":552,"props":1422,"children":1424},{"className":1423},[],[1425],{"type":419,"value":1426},".gitattributes",{"type":419,"value":1428}," with ",{"type":413,"tag":552,"props":1430,"children":1432},{"className":1431},[],[1433],{"type":419,"value":1434},"text=auto",{"type":419,"value":1436}," in it).",{"type":413,"tag":509,"props":1438,"children":1439},{"icon":511},[1440],{"type":413,"tag":422,"props":1441,"children":1442},{},[1443,1445,1452],{"type":419,"value":1444},"As I was writing these lines, I just saw an article from Scott Hanselman about ",{"type":413,"tag":452,"props":1446,"children":1449},{"href":1447,"rel":1448},"https://www.hanselman.com/blog/carriage-returns-and-line-feeds-will-ultimately-bite-you-some-git-tips",[456],[1450],{"type":419,"value":1451},"Carriage Returns and Line Feeds",{"type":419,"value":1453},", if you want to read more about it.",{"type":413,"tag":414,"props":1455,"children":1457},{"id":1456},"dotnetconf-playlist",[1458],{"type":419,"value":1459},"dotNetConf playlist",{"type":413,"tag":422,"props":1461,"children":1462},{},[1463,1465,1471],{"type":419,"value":1464},"dotNetConf was this week and the replays are available ",{"type":413,"tag":452,"props":1466,"children":1469},{"href":1467,"rel":1468},"https://www.youtube.com/playlist?list=PLdo4fOcmZ0oVFtp9MDEBNbA2sSqYvXSXO",[456],[1470],{"type":419,"value":1158},{"type":419,"value":1472}," if you want to watch some talks you missed.",{"type":413,"tag":422,"props":1474,"children":1475},{},[1476],{"type":413,"tag":522,"props":1477,"children":1481},{"alt":1478,"className":1479,"src":1480},".NET Conf 2021 YouTube playlist.",[526,527],"/posts/images/w452021tips_dotnetconf_1.png",[],{"type":413,"tag":422,"props":1483,"children":1484},{},[1485],{"type":419,"value":1217},{"title":401,"searchDepth":742,"depth":742,"links":1487},[1488,1490,1491,1492,1493],{"id":1236,"depth":742,"text":1489},"Vue Devtools, a must-have browser extension when using Vue.js",{"id":1300,"depth":742,"text":1303},{"id":1361,"depth":742,"text":1364},{"id":1377,"depth":742,"text":1380},{"id":1456,"depth":742,"text":1459},"content:1.posts:28.w45-2021-tips-learned-this-week.md","1.posts/28.w45-2021-tips-learned-this-week.md",1716749600676]