Die Agentur
Kompetenzen

Anfrage senden

Senden Sie uns eine unverbindliche Anfrage.
Wir beraten Sie gerne.







    asd

    blog

    Eine kleine Einführung in PowerShell Skripte

    PowerShell ist ein sehr mächtiges Werkzeug, egal was man damit anstellen möchte. Das Anwendungsgebiet ist einfach gigantisch. Vielleicht fällt es deswegen dem einen oder anderen auch so schwer wie mir einen Einstieg in die richtige Syntax zu finden, wenn es einfach darum geht Daten auszuwerten. Denn anders als für gewöhnliche Programmiersprachen bin ich noch nicht auf eine einfache Einführung gestoßen. Dieser Beitrag soll das nachholen. Ich werde versuchen die Syntax zu erklären und anhand von einfachen Beispielen zu erklären, wie man durch Probieren und Beobachten zu den gewünschten Ergebnissen gelangt.

    Dieser Beitrag soll in erster Linie diejenigen unter euch unterstützen, die via PowerShell Datenerfassen und ausgeben wollen. Die Anwendungsmöglichkeiten von PowerShell sind zu komplex um sie in einen Guide zu packen.

    1. Variablen, Objekte, Kommentare

    Variablen werden einfach mit einem $ Zeichen markiert. Der Aufruf von Variablen und das Setzen von Werten ist erstmal nichts besonderes.

    #Das ist ein Kommentar
    
    <# Das
    ist ein längerer Kommentar
    #>
    
    #eine beliebige Variable
    $anyVar
    
    #explizit als String deklarierte Variable
    [String] $StringVar
    
    #implizit als String angelegte Variable
    $variable = 'Das ist ein String'
    
    #implizit als Int32 angelegte Variable
    $var2 = 2 

    Boolsche Werte setzt man in PowerShell mit $true oder $false.

    $boolean = $true

    Eine Konsolenausgabe erhalten wir mit Write Host

    >> Write-Host 'Ich werde in der Konsole ausgegeben
    << Ich werde in der Konsole ausgegeben

    Spannend wird es bei Arrays und Objekten. Ein Array kann direkt als solches deklariert werden, ohne Deklaration wird es aber als Object Array angelegt. Wir können ein Array mit Werten bestücken, oder auch abkürzen:

    #explizit deklarierters Int32 Array
    [int[]] $integerArray = 1,2,3,4,5,6,7,8,9
    
    #ObjectArray
    $objectArray = 1,2,3,4,5,6,7,8,9
    
    #Array mit Werten [1,2,3,4,5,6,7,8,9]
    shortCutArray = 1..9

    Strings lassen sich mit dem ‚+‘ Operator verketten

    $var1 = 'Hello'
    $var2 = '!'
    $var3 = $var1 + ' World' + $var2
    >> $var3
    << Hello World!

    Eine Integer Variable wird auch einfach über ‚++‘ inkrementiert und mit ‚–‚ dekrementiert

    $zahl = 1
    
    $zahl++
    >> $zahl
    << 2
    
    $zahl--
    >> $zahl
    << 1

    Hier eine kleine Auswahl der wichtigsten Datentypen

    DeklarationBeschreibung
    [Array]Array
    [Bool]True/False
    [Int32]/[Int]Ganzzahl
    [PsObject]Object
    [String]Zeichenkette
    [Float]Fließkommazahl

    Ein leeres Object Array könnt ihr einfach folgendermaßen erstellen. Es ist sehr nützlich um gesammelte Daten wie in einem Array zu bündeln, durchzuiterieren oder auszugeben:

    $newEmptyObjectArray = @()

    Einem Array können andere Objekte einfach hinzugefügt werden

    $newEmptyObjectArray += 'ich werde hinzugefuegt'

    Eine Abfrage erfolgt wie gewohnt

    >> $newEmptyObjectArray[0]
    << ich werde hinzugefuegt

    Spannend sind auch die PSCustomObjects für Datensammler:

    #Objekt anlegen
    $newObject = New-Object PSCustomObject
    
    #Wert hinzufügen
    $newObject | Add-Member -type NoteProperty -name 'Name' -value 'Wert'
    
    #Wert abfragen
    >> $newObject.Name
    << Wert
    
    #Object abfragen
    >> $newObject
    << Name
       -----
       Wert

    2. Schleifen und Verzweigungen

    If und Else funktionieren gewöhnlich. Dafür sind die Vergleichsoperatoren für den gemeinen Javaprogrammierer gewöhnungsbedürftig:

    if($true){
        #do something
    }else if($false){
        #do something else
    }else{
        #do something different
    }
    #if(1 == 1)
    if(1 -eq 1)
    
    #if(4 > 1)
    if(4 -gt 1)
    
    #if(1 < 5)
    if(1 -lt 5)
    
    #if(1 != 2)
    if(1 -ne 2)
    
    #Ein Switch sieht so aus
    $switchVariable = 5
    switch ($switchVariable){
        1 { Write-Host 'Ich werde bei 1 ausgegeben' }
        5 { Write-Host 'Ich werde bei 5 ausgegeben' }
        Default { Write-Host 'Ich werde ausgegeben, wenn nichts passt' }
    }
    

    While-, For- oder Foreach Schleifen gibt es auch

    While($true){
       #do something
    }
    
    $Numbers = 1..9
    ForEach($Number in $Numbers){
        Write-Host $Number
    }

    Fortsetzung folgt…

    Wir beschäftigen uns bald noch mit weiteren Themen wie:

    • Parameterübergabe
    • Weitere Schleifenarten
    • Filter
    • Nutzereingaben
    • Date
    • Try/Catch
    • CSV Export

    React.js – Server-Side Rendering A bis Z 2019

    Mit etwas Kreativität eignet sich React für eine Vielzahl von Anwendungsmöglichkeiten. Doch dem Standard Package sind gewisse Grenzen gesetzt. Spätestens beim Thema SEO und HTTP Status Codes stoßen wir schnell an unsere Grenzen. Mit Server-Side Rendering können wir einige Klippen umschiffen. Dieser Guide soll euch eine Vorstellung geben wie ihr euer eigenes Boilerplate für React mit Server Side Rendering erstellt, ordentlich konfiguriert und möglichst komfortabel an eurer App arbeiten könnt, fast wie mit dem Standard CRA Package.

    Das Problem – Client Side Rendering

    React wird wie die meisten Javascript Frameworks Clientseitig gerendert. Eure Nutzer bekommen beim Aufruf eurer Website also erstmal eure komplette „Web-app“, aber nur eine sperrliche Index.html. Sobald alles geladen wurde übernimmt React und füllt eure Seite, aber eben Clientseitig. Das bedeutet zum einen, dass der Server nicht mehr gefragt wird, ob eine Seite existiert oder weiterleitet etc. Zum anderen sind Suchmaschinen meiner Erfahrung nach noch nicht darauf ausgelegt euren Javascript Code auszuführen. Suchmaschinen werden also immer nur im ersten Durchlauf eure leere Index.html lesen und keinen Informationsgehalt daraus ziehen. Das hat weiter zur Folge, dass die Suchmaschine den Inhalt verschiedener Unterseiten nicht unterscheiden kann und euch im Worst Case für doppelten Content abstraft. Das mag sich in Zukunft ändern, aber so lange Suchmaschinen euren Javascript Code nicht interpretieren bleibt euch keine andere Wahl als auf statische Seiten zu setzen oder serverseitig zu rendern.

    Die Lösung

    Wir werden einen Server aufsetzen, der die URL interpretiert, den passenden Inhalt auf dem Server rendert und das vollständige Ergebnis an den User oder die Suchmaschine übergibt. Für den User macht es im weiteren Verlauf keinen Unterschied. Sobald die Seite geladen wurde wird wie gewohnt React übernehmen und flüssig und schnell den Content bereitstellen. Suchmaschinen sind für die Bereitstellung des Inhalts aber äußerst dankbar. Denn auch sie bekommen den gerenderten Inhalt zu sehen. Des Weiteren habt ihr so die Möglichkeit HTTP Statuscodes zu setzen, z.B. für Seiten die nicht verfügbar sind einen 404 zu versenden. Darüber hinaus könnt ihr euch für jede Seite um SEO Inhalte bemühen wie Metatags und strukturierte Daten.

    1. Projekt Initialisieren

    Leg einen neuen Ordner für dein Projekt an, öffne ihn in einem Codeeditor deiner Wahl (ich empfehle Visual Studio Code) und initiiere dein Projekt

    npm init

    Dieser Vorgang erstellt euer package.json. Diese sieht ähnlich aus wie folgende:

    package.json
    {
      "name": "blog",
      "version": "1.0.0",
      "description": "test",
      "main": "src/server/server.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "Christian Figul",
      "license": "MIT"
    }

    2. Server aufsetzen

    In eurem Projektordner erstellt ihr einen Ordner /src und darin einen Ordner /server. Darin erstellt ihr eine Datei server.js.
    Die Ordnerstruktur sieht nun so aus:

    Projectfolder
    |-package.json
    |-src
    ||-server
    |||-server.js

    Für den Anfang installieren wir express.js als Server.

    npm i express --save

    öffnet nun server.js und setzt den Server auf:

    const express = require('express')
    
    const app = express();
    const PORT = process.env.PORT || 3000;
    
    app.listen(PORT,()=>{
        console.log(`App running ${PORT}`)
    })

    Wenn wir später Webpack mit Babel installieren können wir die Syntax auf die gewohnte ES6 Syntax abändern. Für den Moment sollte es aber genügen. Wir können unseren Server starten und testen.
    Startet den Server mit

    node src/server/server.js

    Öffnet einen Browser und ruft die Seite localhost:3000 auf. Dort wird die Meldung Cannot GET / erscheinen. Daran arbeiten wir als nächstes.

    3. Serverseitig rendern

    Wir bleiben in server.js und fügen nach dem PORT und vor app.listen... folgende Zeilen ein:

    ...
    app.get('*', (req,res)=>{
        const html = `
        <!DOCTYPE html>
        <html lang="de">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
            <h1>Hello Server</h1>
        </body>
        </html> 
        `
        res.send(html)
    })
    ...

    Achtet auf die „ bei der html Konstanten.

    app.get(...) fängt alle URL Abfragen ab und verarbeitet diese. Mit res.send() senden wir die Antwort vom Server. In diesem Fall senden wir den Inhalt der Variable html. Diese wird unsere index.html ersetzen, die wir aus dem Standard CRA Package kennen.

    Ein neuer Test mach deutlich was wir gemacht haben. Startet den Server erneut wie oben beschrieben. Geht auf die Seite und siehe da…Hello Server sollte euch nun begrüßen.

    4. React einbinden

    Jetzt wird es spannend. Wir legen einen neuen Ordner /client im src-Ordner an. Darin erstellen wir die folgenden 3 Dateien: index.js, App.js und index.css. Eure Ordnerstruktur sieht nun so aus:

    Projectfolder
    |-package.json
    |-src
    ||-server
    |||-server.js
    ||-client
    |||-App.js
    |||-index.css
    |||-index.js

    Nun installieren wir die notwendigen Pakete für React und React-Router:

    • react
    • react-router
    • react-router-dom
    • react-dom
    npm i react react-router react-router-dom react-dom

    Die App.js könnt ihr fast identisch zum CRA – Standard anlegen. Wir wollen aber gleich den <Switch> und die erste <Route /> anlegen, damit wir gleich den Router integrieren:

    import React, {Component} from 'react';
    import{Route,Switch} from 'react-router-dom';
    
    class App extends Component{
        render(){
            return (
                <Switch>
                    <Route exact path='/' render={props=>(
                        <h1>Hello React from Server</h1>
                    )}/>
                </Switch>
            )
        }
    }
    export default App;

    Die index.js sieht ebenfalls fast wie das CRA Original aus. Wir verwenden allerdings hydrate statt render, damit React nur den Teil des DOMs updatet, der sich tatsächlich vom Original unterscheidet. An dieser Stelle wickeln wir die <App /> auch gleich in den <BrowserRouter> ein:

    import React from 'react'
    import ReactDOM from 'react-dom'
    import './index.css'
    import App from './App'
    import {BrowserRouter} from 'react-router-dom'
    
    ReactDOM.hydrate(
        <BrowserRouter>
            <App />
        </BrowserRouter>
    , document.getElementById('root'));

    In der index.css könnt ihr euch austoben wie ihr wollt. Wir kommen später zu einigen Besonderheiten.

    Nun sind ein paar Anpassungen an server.js notwendig, damit der Server die React App rendert und das Ergebnis an den Client sendet:

    import express from 'express';
    import React from 'react';
    import ReactDOMServer from 'react-dom/server';
    import App from '../client/App'
    import {StaticRouter} from 'react-router';
    
    const app = express();
    const PORT = process.env.PORT || 3000;
    
    app.get('*', (req,res)=>{
        const context = {}
        const content = ReactDOMServer.renderToString(
            <StaticRouter location={req.url} context={context}>
                <App />
            </StaticRouter>
        )
    
        const html = `
        <!DOCTYPE html>
        <html lang="de">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Document</title>
        </head>
        <body>
            <div id='root'>${content}</div>
        </body>
        </html> 
        `
    
        res.send(html)
    })

    Gehen wir die Änderungen durch:

    import express from 'express';
    import React from 'react';
    import ReactDOMServer from 'react-dom/server';
    import App from '../client/App'
    import {StaticRouter} from 'react-router';

    Wir ändern schon mal die Syntax zu ES6. So wird aus

    const express = require('express') --> import express from 'express';

    Dazu kommen die Importe für unsere React App.
    In der app.get(...) Methode ergänzen wir die Konstanten context, die für den HTTP Status Code relevant wird und erzeugen in content mit der renderToString() Methode, dem <StaticRouter>und der location unseren eigentlichen Inhalt für die Seite.
    Im html Boilerplate richten wir das bekannte <div id='root'> ein, welches Clientseitig verwendet wird um den Inhalt clientseitig zu rendern.
    Innerhalb des Tags setzen wir den ${content} als variable. Dieser wird den angefragten Inhalt, der serverseitig gerendert wurde initial an den Client übergeben. So kann auch eine Suchmaschine euren Inhalt lesen, denn sie bekommt den kompletten angefragten Content direkt vom Server. Interagiert euer User nun weiter mit der Seite, wird React mit dem <div id='root'> Container wie gewohnt arbeiten können.

    Noch können wir es nicht testen, denn euer Server kann die ES6 Syntax nicht interpretieren. Darum kümmern wir uns im nächsten Schritt.

    5. Webpack und Babel installieren und einrichten

    Erst mal brauchen wir eine ganze reihe von DevDependencies:

    • @babel/core
    • @babel/preset-env
    • @babel/preset-react
    • babel-loader
    • webpack
    • webpack-cli
    • mini-css-extract-plugin
    • css-loader
    • clean-webpack-plugin
    npm i --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli mini-css-extract-plugin css-loader clean-webpack-plugin

    Außerdem verwenden wir nodemon um den Server automatisch zu starten:

    npm i nodemon

    Das ist eine Menge, achtet bei der Installation auf --save-dev und auf die richtige Schreibweise. Dieser Guide bezieht sich auf die aktuellen Versionen von 2019. Es hat mich bei der Suche nach einem Tutorial wahnsinnig gemacht, dass größtenteils veraltete Versionen und damit auch veraltete Herangehensweisen verwendet wurden. Achtet also bitte auf die Versionen. Hier ist meine package.json damit ihr euch orientieren könnt. Weichen eure Versionen zu sehr ab, könnte es sein, dass es so nicht mehr funktioniert. Ich werde mich bemühen diesen Beitrag zu updaten, wenn sich grundlegend etwas ändert:

    {
      "name": "blog",
      "version": "1.0.0",
      "description": "test",
      "main": "src/server/server.js",
      "scripts": {
        "webpack:build": "webpack --mode development --config webpack.config.js ",
        "server": "nodemon ./dist/main.js"
      },
      "author": "Christian Figul",
      "license": "MIT",
      "dependencies": {
        "express": "^4.17.1",
        "nodemon": "^1.19.2",
        "react": "^16.9.0",
        "react-dom": "^16.9.0",
        "react-router": "^5.1.0",
        "react-router-dom": "^5.1.0"
      },
      "devDependencies": {
        "@babel/core": "^7.6.2",
        "@babel/plugin-proposal-class-properties": "^7.5.5",
        "@babel/preset-env": "^7.6.2",
        "@babel/preset-react": "^7.0.0",
        "babel-loader": "^8.0.6",
        "clean-webpack-plugin": "^3.0.0",
        "css-loader": "^3.2.0",
        "mini-css-extract-plugin": "^0.8.0",
        "webpack": "^4.41.0",
        "webpack-cli": "^3.3.9"
      }
    }

    Webpack benutzen wir zum einen um den babel-loader einzubinden, der die ES6 Syntax für den Browser interpretierbar macht. Außerdem nutzen wir Webpack um ein fertiges Build erstellen zu können, welches ihr dann auf euren Server schieben könnt, assets wie css und später auch Bilder oder Schriften sauber zu organisieren und einzubinden.

    In eurem Stammverzeichnis benötigen wir jetzt zwei neue Dateien:

    • .babelrc
    • webpack.config.js

    Euer Projektordner sieht nun also so aus:

    Projectfolder
    |-.babelrc
    |-webpack.config.js
    |-package.json
    |-src
    ||-server
    |||-server.js
    ||-client
    |||-App.js
    |||-index.css
    |||-index.js

    In eure .babelrc schreibt ihr folgende Zeilen:

    {
      "presets": ["@babel/preset-env", "@babel/preset-react"],
      "plugins": [
        ["@babel/plugin-proposal-class-properties", { "loose": false }]
      ]
    }

    Eure webpack.config.js kann folgendermaßen aussehen:

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    
    var path = require('path');
    
    const server = {
        target:'node',
        node:{
            __dirname:false
        },
        entry:{
            '../server':  './src/server/server.js',
            'client': './src/client/index.js'
        },
        module:{
            rules:[
                {
                    test: /\.(js|jsx)$/,
                    exclude:/node_modules/,
                    use:{loader:"babel-loader"}
                },
                {
                    test: /\.css$/,
                    use:[
                        {loader: MiniCssExtractPlugin.loader},
                        {loader: 'css-loader'}
                    ]
                }
            ]
        },
        plugins: [
            new CleanWebpackPlugin(),
            new MiniCssExtractPlugin({
                filename: '[name].css',
                chunkFilename: '[id].css',
                ignoreOrder: false
            }),
        ],
        output:{
            filename:'[name].js',
            path:path.resolve(__dirname,'dist', 'public')
        }
    }
    
    module.exports = server

    Zu Beginn werden die Plugins geladen. Die path Variable brauchen wir für den aktuellen Verzeichnis Pfad. __dirname setzen wir auf false, weil ihr sonst Probleme mit der richtigen Verzeichnisangabe bekommt. Entry ist einmal euer Server mit server.js und euer Client mit index.js.

    In den Modulen übersetzen wir alle .js oder .jsx Dateien mit dem babel-loader. .css Dateien werden mit dem MiniCssExtractPlugin.loader verarbeitet. In den Plugin Einstellungen verwenden wir CleanWebpackPlugin, damit sich euer Build ordner immer säubert, bevor ihr ein neues Build erstellt, damit keine alten Dateien da drin rum liegen. Wir setzen ignoreOrder auf false, damit Klassennamen in der CSS Datei nicht umbenannt werden, was sonst die normale Folge wäre.

    Ihr könnt bei der Vergabe der Output Namen frei entscheiden wie die Dateien heißen sollen und wo sie liegen. Wenn ihr einfach diesem Guide weiter folgen wollt, empfehle ich diese Angaben nicht zu ändern.

    Nun richten wir uns noch in der package.json zwei Skripte ein, die uns die Arbeit etwas leichter machen:

    "scripts": {
        "webpack:build": "webpack --mode development --config webpack.config.js ",
        "server": "nodemon ./dist/main.js"
      },

    Vielleicht habt ihr sie oben schon bemerkt. Das webpack:build erzeugt euch ein Build, welches auf einen echten Server geladen werden kann. Mit server wird diese Version dann gestartet.

    Ereugt nun euer erstes Build und startet dann euren Server:

    npm run webpack:build
    npm run server

    Wenn alles gut gegangen ist, könnt ihr nun euer Ergebnis im Browser bewundern. Vielleicht sieht es noch nicht anders aus als vorher, aber es ist ein gewaltiger unterschied. Schaut euch den Source-Code an. Dort wird der Inhalt aus eurer App.js Datei angezeigt. Dieser wurde erst gerendert und dann an den Browser übergeben. Mit der Standard CRA, würdet ihr im Source-Code nur den leeren <div id='root'> Container sehen.

    6. React Funktionalität übertragen

    Ein wichtiger Schritt in der server.js steht noch aus, damit React wie gewohnt in eurer App funktioniert:

    import ...
    ...
    app.use(express.static('dist/public'))
    app.get(...
        const html = `
        <!DOCTYPE html>
        <html lang="de">
        <head>
            ...
            <link href="client.css" rel="stylesheet">
        </head>
        <body>
            <div id='root'>${content}</div>
            <script type="text/javascript" src="client.js"></script>
        </body>
        </html> 
        `
        res.send(html)
    })
    ...

    Vor app.get(...) ergänzt ihr app.use(...) und legt damit den öffentlichen Pfad eurer App fest, damit niemand Zugriff auf die server.js eures Buildordners bekommt, denn dort können sensible Daten abgelegt sein.
    Im html Boilerplate ergänzt ihr noch das Script zu eurer client.js um die React Funktionalität zu ergänzen.

    Das wars schon

    Ihr habt eine lauffähige, serverseitig gerenderte React App. In den nächsten Folgen bauen wir auf dieser Struktur auf und bauen unsere App weiter auf. Wir behandeln HTTP Status Codes, dynamische Metatags, Strukturierte Daten und binden weitere Assets wie Schriften und Bilder ein. Wir kümmern uns um Redux und Material-UI und ich zeige euch so, wie ihr eigentlich schon ab diesem Zeitpunkt wie gewohnt weiter entwickeln könnt und am wie man einen express Server selber hosten kann, ohne Heroku oder andere Dienstleister.