Friday, 22 May 2020

Jest-diff Issue after upgrading react-scripts


A project I have been working on recently based on CRA (create-react-app) for TypeScript needed a large jump upgrade (3.1.1 to 3.4.0). Finally after working through a lot of other well documented problems I hit this one:

'=' expected. TS1005

The error occuring in the file jest-diff line 1:
import type { DiffOptions } from './types'

This was strange to me because I had not changed anything related to jest or my testing setup. 

Luckily I was able to find this github issue: https://github.com/facebook/jest/issues/9703

The user paulconlin got it spot on- I upgraded to TypeScript 3.8.3 and was able to compile again.

Tuesday, 20 August 2019

Excel files with .NET Core

I found myself needing to quickly manipulate some data in an excel sheet.

I had no access to the full blown Visual Studio, no problems I thought, let's see what VSCode, the command line and .NetCore 2 can do.

New project: no problem
Snideness aside it really is easy - just think of a project folder name...

  • dotnet new console 
  • dotnet restore
  • dotnet run

C# 7 has arrived... you no longer need to write this kind of madness:
static Main(string[] args) {
  thingIamDoing.RunAsync().GetAwaiter().GetResult(); 
}

instead:
public static async Task Main(string[] args)
{
   await thingIamDoing();
}
pleasing... but a caveat - you must specify LangVersion  in the csproj as latest to use this:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <LangVersion>latest</LangVersion>
  </PropertyGroup>
</Project>

nuget is yesterdays news... stop using it along with package.config.

instead:
dotnet add package EPPlus.Core
also pleasing... especially as it automatically adds the reference to the csproj:
<ItemGroup> <PackageReference Include="EPPlus.Core" Version="1.5.4" /> </ItemGroup> </Project>

so long package.config

So now I have a library to help me read an xlsx file we can experiment. Can this library tell me how many columns and rows there are?

using System.IO; using System.Text; using System.Threading.Tasks; using OfficeOpenXml; ...
var sFileName = @"test_file.xlsx";
FileInfo file = new FileInfo(Path.Combine("C:\\", sFileName));
var sb = new StringBuilder();

try
{
  using (ExcelPackage package = new ExcelPackage(file))
  {
    ExcelWorksheet worksheet = package.Workbook.Worksheets[4];
    var rowCount = worksheet.Dimension.Rows;
    var colCount = worksheet.Dimension.Columns;
    sb.Append($"{colCount} rows: {rowCount}");
  }
} catch (Exception ex) {
  sb.Append($"An error occurred while importing. {ex.Message}");
}

Console.WriteLine(sb.ToString());

This gives me a result of 13 and 55 rows, which is what I expected.
Interesting to note:

  • The API is not zero based, in the example test_file, there really are 4 worksheets
  • If the excel spreadsheet is open, expect a file IO/lock error

Now I know the number of columns and rows we can simply iterate through the spreadsheet to read the data. e.g.

var headerPrefix = "headerPrefix_";

if (hasHeader) {
  headerPrefix = worksheet.Cells[1, col].Value.ToString();
}

for (int row = hasHeader ? 2 : 1; row <= rowCount; row++)
{
  if (worksheet.Cells[row, col].Value == null) continue;
  var newValue = worksheet.Cells[row, col].Value.ToString();
  
  

To export:

string fileName = @"results.xlsx";
var exportfile = new FileInfo(Path.Combine("C:\\Code\\", fileName));

if (exportfile.Exists)
{
  exportfile.Delete();
  exportfile = new FileInfo(Path.Combine("C:\\Code\\", fileName));
}

using (ExcelPackage package = new ExcelPackage(exportfile))
{
  var worksheet = package.Workbook.Worksheets.Add("results");
  worksheet.Cells[1, 1].Value = "Column 1";

  // continue on to fill out row data things here ....
  // once complete - save
  package.Save();
}

Monday, 5 August 2019

React: Key learning touch points

React itself is a powerful framework including a number of key techniques:
Redux:
  • Saga's versus thunks... or both?
  • Global versus local state... are you over-using redux?
Other learning:
  • Remember that setState() can also take a function as a parameter:
  • this.setState((prevState, props) => ({ ...prevState, answer}));
  • setState() is asynchronous, if you call it in the component you cannot guarantee that local state has been updated immediately

Wednesday, 1 May 2019

React: overkill with Redux and where Portals save the day



Recently I encountered a situation where I needed to overlay a div on top of another div. The standard way to do this is to use CSS and absolute or fixed positioning (https://stackoverflow.com/questions/2941189/how-to-overlay-one-div-over-another-div).

Sounds simple enough, however I need to do this from within a deep hierarchy of elements:

-> Detail Component
  -> Action Bar Component
  -> Items Component: Loop through and display expandable content divs
       -> On Click : overlay a component which is a div containing "expandable content"

The "items" component uses a standard bootstrap table to align the elements like so:
item 1 item 2
item 3 item 4

This layout means that when you select the onClick() for "item 1" and you render the expandable component which is essentially just a div, and it is positioned relatively the the content will appear in place of item one in the table.
item 1
(expandable content)
item 2
item 3item 4


Cut a long story short, every which way I tried to style the popup unwanted styles would be inherited from the table and other components above it. I also found that I had to place it absolutely to get the effect I was looking for which created a raft of further problems. Finally, it was suggested that this might be a good use case for React Portals which did indeed save the day.

I also learned on this project how much Redux can be over utilized. "When you have a hammer, everything starts to look like a nail". This was said a lot, and it should be, because when you are deep into the detail of a project it can be hard to see that it has been over-engineered.

Monday, 6 August 2018

Angular Progressive Web Apps

When in doubt refer to the Offical docs. When that doesn't work - try this manual fix it like I did!

Issues with Angular-cli

First it turns out that using ng add, as below, doesn't work very well.

ng add @angular/pwa --project project_name

I thought that maybe these issues were due a change in the Angular app file hierarchy (I changed "src" to "web"). I don't think this was the problem because many other people got stuck on the same error here and here.

Error highlighted below:
Installing packages for tooling via npm.
+ @angular/pwa@0.7.2
added 2 packages in 12.443s
Installed packages for tooling via npm.
Path "/ngsw-config.json" already exist.
I was able to get going by looking to see what this process is suppose to do.

Luckily it doesn't do a great deal and it is possible to find the files by searching your node_module directory then pasting them in before changing the parameters to suit your project - for example: ngsw-config.json to the code root and manifest.json to the /src directory. 

I was also able to better understand what the process should do by looking closely at this git commit. Notice the process adds:
"buildOptimizer": true,
"serviceWorker": true

to angular.json then adds the manifest.json before referencing it in the index.html:
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#1976d2">

Issues with testing service workers locally (A bad HTTP response code (404) was received when fetching the script)

This is a message you are will most likely see when you are attempting use the angular cli server and PWA. Probably running:

ng serve --prod

This is again a heavily documented issue yet that didn't stop me scratching my head.

ng serve will not run the required service worker compilation only ng build will do that - see.

This article also goes on to explain that only secure origins are allowed for service workers. Please consider whether it is worth the time to get this working too. The chances are that the project will work on a secure, encrypted site already now, if deployed.

Finally, you may get "ngsw.json cannot be found" or "manifest.json cannot be found". This can be remedied in Azure at least by allowing JSON MIME type to be served by the web server. Bear in mind that any other JSON in your dist directory will also be accessible.

<configuration>
    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".json" mimeType="application/json" />
     </staticContent>
    </system.webServer>
</configuration> 

Is it true that service workers only work with transport layer security (TLS or SSL)

No, you can run locally with a local node instance. You can also run chrome with parameters to tell it to always consider localhost secure if you find issues with that. See the official documentation.

Monday, 19 February 2018

The jump between Angular Material 2 Beta 10 and Material Beta 11+

Having just been through this experience I thought I would share some thoughts to help any other early Angular Material adopters navigate their way to the later Beta's - 11 and 12 as well as the subsequent release candidates.

Change 1
Angular Material no longer can be imported into your project as just one module. You must instead select all of the modules which you intend to use in the project.

Change 2 - seemingly innocuous..
The problem with upgrading between these two versions is that the Md prefix has been changed to Mat. This unfortunately now clashes with the AngularJS Material implementation... such as Md2.

We were early adopters of Angular Material, so we are still using Md2 by Promact. Originally this was used as a stopgap while essential components like the date-picker were being completed by the official Angular Material team. However, now, we wish to use both Md2 and Angular Material side by side. Especially since I was originally putting together the project with Angular 4.0.1 and now wish to upgrade to the latest.

ERROR Error: Uncaught (in promise): Error: The "mat-" prefix cannot be used in ng-material v1 compatibility mode.

To get around this you must use the "CompatibilityModule" or "NoConflictStyleCompatibilityMode" or something...?
use compatibility module if you still want to use md- prefix like this
import { CompatibilityModule } from '@angular/material';
and import it in app module
if you want to use new mat- prefix which is good you can
use NoConflictStyleCompatibilityMode like this
import {NoConflictStyleCompatibilityMode} from '@angular/material';
When I first read this comment I was still confused. I just want my solution to work - what is all this!? This comment further down these thread helped me to understand:

Issue 1 thread
Issue 2 thread and relevent comment

I tried importing from material itself but this did not clear the errors.

import { NoConflictStyleCompatibilityMode } from '@angular/material';

Instead the solution seems to be to import and therefore invoke the NoConflictStleCompatibilityMode from MD2.
import { Md2Module, NoConflictStyleCompatibilityMode } from 'md2';

This makes sense because the use of mat in an angular/material v1 context can no only be in the MD2 project.

Wednesday, 12 April 2017

Checking Out React

I started my journey at the React Tutorial Page. While reading the introduction and checking out the code example on Codepen, I then had the notion that seeing as it was a Tic-Tac-Toe game, it might be nice to do it more properly and include it on my website.

Once down this road I then decided it would be good to turn it into a mini project to find out more about yarn and webpack, as these compliment the React world and are the shiny new toys in front-end web development.

This first blog in the series is about the setup.

Notes on Yarn and WebPack
I have heard that Yarn is better than NPM as a package manager, it is faster and more reliable. Webpack is more complex/flexible than Grunt or Gulp as a builder tool but, like my personal favourite JSPM (through systemJS) it is an excellent JavaScript module loader out of the box. Webpack is much more popular than JSPM within the React community.

Back to Tick-Tac-Toe
So I used npm to install yarn, ran yarn init and then used it to bring down my dependencies React and React DOM. I was pleased to find that there is no difference in where the modules are stored - it is still in a folder called "node_modules". I was also aware that I needed to "transpile" the ES2015 React code into ES5 so I installed babel using the "webpack" option on the babel installation page.
npm install --save-dev babel-loader babel-core
Notice that this is based on npm, but this was no problem, you can just replace "npm install" with "yarn add" and the command "--save-dev" with "-D". This was all easy to find here.

Using Webpack to transpile ES2015 back down to ES5
After some research I have found that the best way to use Webpack with babel, karma and react is to use the following packages:



With this setup I was able to setup a simple "hello world" example. I will get into more detail with my next post.