SEO angular en acción:


Trilon.io y el equipo universal Angular mantienen este repositorio y está destinado a ser un iniciador avanzado tanto para ASP.NET Core 2.1 usando Angular 7.0+, no solo para el lado del cliente, sino también para representar en el servidor para pinturas de aplicaciones instantáneas (nota: si no necesita leer SSR aquí sobre cómo deshabilitarlo).
Esta es una aplicación de inicio rica en características que contiene todas las últimas tecnologías, los mejores sistemas de compilación disponibles e incluye muchos ejemplos y bibliotecas del mundo real necesarios en las aplicaciones (SPA) de hoy en día.
Esto utiliza todos los estándares más recientes, sin trago, sin glorieta, sin tipos, sin "construir" manualmente nada. ¡NPM, Webpack y .net manejan todo por usted!
¡Estas son solo algunas de las características que se encuentran en este iniciador!
ASP.NET 2.1 - VS2017 Soporte ahora!
Angular 7.0.0 :
ng gc components/example-componentng gs shared/some-serviceSistema de compilación de Webpack (Webpack 4)
Marcos de prueba
Productividad
ASP.NET Core 2.1
Azur
npm i -S @markpieszak/ng-application-insights como dependencias. // Add the Module to your imports
ApplicationInsightsModule . forRoot ( {
instrumentationKey : 'Your-Application-Insights-instrumentationKey'
} )Estibador
Asegúrese de tener .NET Core 2.1 instalado y/o VS2017 15.3. VS2017 instalará automáticamente todas las dependencias NPM & .NET necesarias cuando abra el proyecto.
¡Simplemente presione F5 para comenzar a depurar!
Docker-Support : Cambie el proyecto de inicio a Docker-Compose y presione F5
Nota : Si obtiene algún error después de esto, como module not found: boot.server (o similar), abra la línea de comandos y ejecute npm run build:dev
Nota: Asegúrese de tener instalado la extensión C# y .NET Core.
El proyecto viene con los archivos Configurado Launch.json para permitirle presionar F5 para iniciar el proyecto.
# cd into the directory you cloned the project into
npm install && npm run build:dev && dotnet restore
# or yarn install Si está ejecutando el proyecto desde la línea de comando con dotnet run asegúrese de establecer sus variables de entorno en el desarrollo (de lo contrario, cosas como HMR podrían no funcionar).
# on Windows:
set ASPNETCORE_ENVIRONMENT=Development
# on Mac/Linux
export ASPNETCORE_ENVIRONMENT=Development Usando dotnet publish , cuando esté terminado, coloque la carpeta generada en su servidor y use IIS para disparar todo.
git remote add azure https://[email protected]:443/my-angular2-site.git
// ^ get this from Azure (Web App Overview section - Git clone url)
git push --set-upstream azure master Nota: Esta aplicación tiene una configuración de WebAPI (nuestra API REST) dentro del mismo proyecto, pero, por supuesto, todo esto podría abstraerse en un proyecto (s) completamente separado (s) idealmente. .NET Core Things se realizan en el mismo proyecto por el bien de la simplicidad.
Archivos de nivel raíz
Aquí tenemos los sospechosos habituales que se encuentran a nivel de raíz.
Archivos orientados al frente:
package.json - Dependencias y scripts del proyecto NPM.tsconfig - Configuración de TypeScript (aquí también configuramos las rutas)webpack : archivos de configuración (agrupación modular + mucho más)karma - Archivos de configuración (prueba unitaria)protractor - Archivos de configuración (prueba E2E)tslint - Reglas de Linting de código TypeScript¡Echemos un vistazo a cómo se estructura esto para que podamos darle sentido a todo!
Con Angular Universal, necesitamos dividir nuestra lógica aplicada por plataforma , por lo que si miramos dentro de esta carpeta, verá los 2 archivos raíz, que ramifican toda la lógica para el navegador y el servidor, respectivamente.
Aquí configuramos algunas cosas, Bootstrapping angular del cliente.
Apenas necesitará tocar este archivo, pero algo a tener en cuenta, este es el archivo donde importaría bibliotecas que solo desea que se use en el navegador. (Solo sepa que tendría que proporcionar una implementación simulada para el servidor al hacerlo).
Observe la estructura de la carpeta aquí en ./ClientApp/ :
+ /ClientApp/
+ /app/
App NgModule - our Root NgModule (you'll insert Components/etc here most often)
AppComponent / App Routes / global css styles
* Notice that we have 2 dividing NgModules:
app.module.browser & app.module.server
You'll almost always be using the common app.module, but these 2 are used to split up platform logic
for situations where you need to use Dependency Injection / etc, between platforms.
Note: You could use whatever folder conventions you'd like, I prefer to split up things in terms of whether they are re-usable
"components" or routeable / page-like components that group together and organize entire sections.
+ + > ++ > /components/
Here are all the regular Components that aren't "Pages" or container Components
+ + > ++ > /containers/
These are the routeable or "Page / Container" Components, sometimes known as "Dumb" Components
+ + > ++ > /shared/
Here we put all shared Services / Directives / Pipes etc Al agregar nuevas características/componentes/etc. a su aplicación, comúnmente agregará cosas a la raíz ngmodule (ubicado en /ClientApp/app/app.module.ts ), pero ¿por qué hay otros dos ngmodules en esta carpeta?
Esto se debe a que queremos dividir nuestra lógica por plataforma , pero observe que ambos comparten el Ngmodule común llamado app.module.ts . Al agregar la mayoría de las cosas a su aplicación, este es el único lugar que tendrá que agregar en su nuevo componente / directiva / tubería / etc. Solo ocasional necesitará agregar manualmente las cosas específicas de la plataforma a cualquier app.module.browser || app.module.server .
Para ilustrar este punto con un ejemplo, puede ver cómo estamos utilizando la inyección de dependencia para inyectar un StorageService que sea diferente para el navegador y el servidor.
// For the Browser (app.module.browser)
{ provide : StorageService , useClass : BrowserStorage }
// For the Server (app.module.server)
{ provide : StorageService , useClass : ServerStorage }Solo recuerde, generalmente solo debe preocuparse por
app.module.ts, ¡ya que ahí es donde agregará la mayoría de sus aplicaciones nuevos aspectos!
Como señalamos, estos están aquí por simplicidades, y de manera realista, es posible que desee proyectos separados para todos sus microservicios / proyectos API REST / etc.
Estamos utilizando MVC dentro de esta aplicación, pero solo necesitamos y tenemos un controlador, llamado HomeController . Aquí es donde toda nuestra aplicación angular se serializa en una cadena, se envía al navegador, junto con todos los activos que necesita luego arrancar en el lado del cliente y convertirse en un spa completo después.
La versión corta es que invocamos ese proceso de nodo, pasando nuestro objeto de solicitud e invocamos el archivo boot.server , y recuperamos un buen objeto que pasamos al objeto .nets ViewData , y espolvorea a través de nuestras Views/Shared/_Layout.cshtml y /Views/Home/index.cshtml !
Aquí se puede encontrar una explicación más detallada: readme de ingenio ng-aspnetcore
// Prerender / Serialize application
var prerenderResult = await Prerenderer . RenderToString (
/* all of our parameters / options / boot.server file / customData object goes here */
) ;
ViewData [ "SpaHtml" ] = prerenderResult . Html ;
ViewData [ "Title" ] = prerenderResult . Globals [ "title" ] ;
ViewData [ "Styles" ] = prerenderResult . Globals [ "styles" ] ;
ViewData [ "Meta" ] = prerenderResult . Globals [ "meta" ] ;
ViewData [ "Links" ] = prerenderResult . Globals [ "links" ] ;
return View ( ) ; // let's render the MVC View ¡Eche un vistazo al archivo _Layout.cshtml , por ejemplo, observe cómo dejamos que .NET maneje e inyecte toda nuestra magia SEO (que extrajimos de Angular)!
<!DOCTYPE html >
< html >
< head >
< base href =" / " />
<!-- Title will be the one you set in your Angular application -->
< title > @ViewData["Title"] - AspNET.Core Angular 7.0.0 (+) starter </ title >
< meta charset =" utf-8 " />
< meta name =" viewport " content =" width=device-width, initial-scale=1.0 " />
@Html.Raw(ViewData["Meta"]) <!-- <meta /> tags -->
@Html.Raw(ViewData["Links"]) <!-- <link /> tags -->
< link rel =" stylesheet " href =" ~/dist/vendor.css " asp-append-version =" true " />
@Html.Raw(ViewData["Styles"]) <!-- <style /> tags -->
</ head >
... etc ... Nuestras Views/Home/index.cshtml simplemente renderiza la aplicación y sirve los archivos web bundled en ella.
@Html.Raw(ViewData["SpaHtml"])
< script src =" ~/dist/vendor.js " asp-append-version =" true " > </ script >
@section scripts {
< script src =" ~/dist/main-client.js " asp-append-version =" true " > </ script >
}Bueno, ahora, su angular del lado del cliente se hará cargo y tendrá un spa completamente funcional. (¡Pero ganamos todos estos excelentes beneficios de SEO de ser renderizados en el servidor)!
Al construir componentes en Angular 7, hay algunas cosas a tener en cuenta.
Asegúrese de proporcionar URL absolutas al llamar a cualquier API. (El servidor no puede entender las rutas relativas, así /api/whatever que falle).
Las llamadas de API se ejecutarán durante un servidor, y una vez más durante el renderizado del cliente, así que asegúrese de usar datos de transferencia que sean importantes para usted para que no vea un parpadeo.
window , document , navigator y otros tipos de navegador ( no existen en el servidor , por lo que usarlos o cualquier biblioteca que los use (jQuery, por ejemplo) no funcionará. Tiene algunas opciones, si realmente necesita algo de esta funcionalidad:
import { PLATFORM_ID } from '@angular/core' ;
import { isPlatformBrowser , isPlatformServer } from '@angular/common' ;
constructor ( @ Inject ( PLATFORM_ID ) private platformId : Object ) { ... }
ngOnInit ( ) {
if ( isPlatformBrowser ( this . platformId ) ) {
// Client only code.
...
}
if ( isPlatformServer ( this . platformId ) ) {
// Server only code.
...
}
}setTimeout . Reducirá el proceso de representación del lado del servidor. Asegúrese de eliminarlos ngOnDestroy en los componentes.No manipules el elemento nativo directamente . Use el renderer2 . Hacemos esto para asegurarnos de que en cualquier entorno podamos cambiar nuestra vista.
constructor ( element : ElementRef , renderer : Renderer2 ) {
this . renderer . setStyle ( element . nativeElement , 'font-size' , 'x-large' ) ;
}sass-loader requiere node-sass > = 4: ya sea en el contenedor Docker o Localhost ejecute NPM Rebuild Node-Sass -F Simplemente comente la lógica dentro de HomeController y reemplace @Html.Raw(ViewData["SpaHtml"]) con solo sus aplicaciones la etiqueta Root AppComponent ("App-Root" en nuestro caso): <app-root></app-root> .
También puede eliminar cualquier lógica
isPlatformBrowser/etc, y eliminar los archivos boot.server, app.module.browser y app.module.server, solo asegúrese de que su archivoboot.browserapunte aapp.module.
Verifique los gotchas sobre cómo usar isPlatformBrowser() .
Querrá eliminar la SSR por ahora, o esperar ya que el soporte debería llegar a manejar la representación de servidor de plataforma. Esto ahora es posible, con los cambios de material angular recientemente actualizado. No tenemos un tutorial disponible para esto todavía.
Nota: Si es posible, intente evitar usar jQuery o bibliotecas que dependan de ello, ya que hay formas mejores y más abstractas de tratar con el DOM en Angular (5+), como usar el renderizador, etc.
Sí, por supuesto, pero hay algunas cosas que debe configurar antes de hacerlo. Primero, asegúrese de que JQuery esté incluido en el archivo de proveedores Webpack, y que tenga una configuración de complemento Webpack para ello. new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' })
Ahora, asegúrese de que cualquier "complemento", etc. que tenga, solo estén incluidos en su archivo boot.browser.ts . (es decir: import 'slick-carousel'; ) En un componente que desea usar jQuery, asegúrese de importarlo cerca de la parte superior así:
import * as $ from 'jquery' ; ¡Siempre asegúrese de envolver cualquier cosa orientada en JQuery en el condicional de Angular isPlatformBrowser() !
Para admitir IE9 a través de IE11, abra el archivo polyfills.ts en la carpeta polyfills y desencadene los 'Polyfills de importación' según sea necesario. Además, asegúrese de que su webpack.config y webpack.config.vendor cambie la opción de TerserPlugin de ecma: 6 a ecma: 5 .
Muchas gracias a Steve Sanderson (@stevesandersonms) de Microsoft y su increíble trabajo en JavaScriptServices e integrando el mundo del nodo con ASP.NET Core.
¡También gracias a los muchos contribuyentes!
Mira nuestros problemas más fáciles aquí
Nada es perfecto, pero hágamelo saber creando un problema (asegúrese de que ya no haya uno existente al respecto), ¡e intentaremos resolver una solución! Si tiene buenas ideas o desea contribuir, no dude en hacer un problema con la propuesta o simplemente hacer un PR de su horquilla.
Copyright (c) 2016-2019 Mark Pieszak
¡Mira trilon.io para obtener más información! Twitter @trilon_io
Contáctenos en [email protected], y hablemos sobre las necesidades de sus proyectos.
Twitter: @trilon_io