استفاده از Angular Universal برای حل مشکل سئو در انگولار
Angular Universal (همچنین با عنوان Server-side rendering هم شناخته می شود) ابزاری است که به سرور اجازه می دهد تا برنامه انگولار را در اولین باری که کاربر از سایت دیدن می کند، pre-render کند. استفاده از server-side rendering می تواند باعث بهبود SEO و افزایش کارایی برنامه مفید باشد. در این آموزش مراحل نصب و پیاده سازی Angular Universal در یک پروژه انگولار را بررسی خواهیم کرد.
Angular Universal در انگولار 9
ابتدا با استفاده از دستور زیر یک پروژه جدید ایجاد کنید.
1 | ng new project-name --style=scss |
سپس با استفاده از دستور زیر Angular-Universal را به پروژه ای که ایجاد کردید، اضافه کنید.
1 | ng add @nguniversal/express-engine --clientProject project-name |
با اجرای دستور فوق، فایل های زیر ایجاد و یا به روز رسانی می شوند.
1 2 3 4 5 6 7 8 | CREATE src/main.server.ts (298 bytes) CREATE src/app/app.server.module.ts (318 bytes) CREATE tsconfig.server.json (325 bytes) CREATE server.ts (2015 bytes) UPDATE package.json (2110 bytes) UPDATE angular.json (5247 bytes) UPDATE src/main.ts (432 bytes) UPDATE src/app/app.module.ts (359 bytes) |
حال اگر مراحل فوق را به درستی انجام داده باشید، می توانید با استفاده از دستور زیر پروژه خود را تست کنید.
1 | npm run build:ssr && npm run serve:ssr |
Angular Universal در انگولار 8 و نسخه های قدیمی تر
ابتدا با استفاده از دستور زیر یک پروژه جدید ایجاد کنید.
1 | ng new project-name --style=scss |
سپس با استفاده از دستورهای زیر وابستگی ها و بسته های مورد نیاز را نصب کنید.
1 2 3 | cd project-name npm install --save @angular/platform-server @nguniversal/module-map-ngfactory-loader ts-loader@4.0.0 express webpack-node-externals ng generate universal project-name --client-project project-name |
با اجرای دستورهای فوق، فایل های زیر ایجاد و یا به روز رسانی می شوند.
1 2 3 4 5 6 7 | CREATE src/main.server.ts (220 bytes) CREATE src/app/app.server.module.ts (318 bytes) CREATE src/tsconfig.server.json (245 bytes) UPDATE package.json (1476 bytes) UPDATE angular.json (3880 bytes) UPDATE src/main.ts (430 bytes) UPDATE src/app/app.module.ts (359 bytes) |
ایجاد فایل server.ts
در پوشه ریشه پروژه خود یک فایل با نام server.ts ایجاد کرده و محتوای آن را به صورت زیر تغییر دهید. این فایل برای هندل کردن server-side rendering استفاده خواهد شد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | // These are important and needed before anything else import "zone.js/dist/zone-node"; import "reflect-metadata"; import { renderModuleFactory } from "@angular/platform-server"; import { enableProdMode } from "@angular/core"; import * as express from "express"; import { join } from "path"; import { readFileSync } from "fs"; const domino = require("domino"); const fs = require("fs"); const path = require("path"); // Faster server renders w/ Prod mode (dev mode never needed) enableProdMode(); // Express server const app = express(); const PORT = process.env.PORT || 4201; const DIST_FOLDER = join(process.cwd(), "dist/browser"); // Our index.html we'll use as our template const template = readFileSync(join(DIST_FOLDER, "index.html")).toString(); const win = domino.createWindow(template); global["window"] = win; global["Node"] = win.Node; global["navigator"] = win.navigator; global["Event"] = win.Event; global["Event"]["prototype"] = win.Event.prototype; global["document"] = win.document; // * NOTE :: leave this as require() since this file is built Dynamically from webpack const { AppServerModuleNgFactory, LAZY_MODULE_MAP, } = require("./dist/server/main"); const { provideModuleMap, } = require("@nguniversal/module-map-ngfactory-loader"); app.engine("html", (_, options, callback) => { renderModuleFactory(AppServerModuleNgFactory, { // Our index.html document: template, url: options.req.url, // DI so that we can get lazy-loading to work differently (since we need it to just instantly render it) extraProviders: [provideModuleMap(LAZY_MODULE_MAP)], }).then((html) => { callback(null, html); }); }); app.set("view engine", "html"); app.set("views", DIST_FOLDER); // Server static files from dist folder app.get("*.*", express.static(DIST_FOLDER)); // All regular routes use the Universal engine app.get("*", (req, res) => { res.render("index", { req }); }); // Start up the Node server app.listen(PORT, () => { console.log(`Node server listening on http://localhost:${PORT}`); }); |
ایجاد فایل webpack.server.config
دوباره در پوشه روت پروژه یک فایل جدید با نام webpack.server.config.js ایجاد کرده و محتوای آن را به صورت زیر تغییر دهید. فایل server.ts به منظور تبدیل کدها به JavaScript به webpack نیاز دارد.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | // Work around for https://github.com/angular/angular-cli/issues/7200 const path = require("path"); const webpack = require("webpack"); const nodeExternals = require("webpack-node-externals"); module.exports = { mode: "none", entry: { // This is our Express server for Dynamic universal server: "./server.ts", // This is an example of Static prerendering (generative) }, target: "node", resolve: { extensions: [".ts", ".js"] }, // Make sure we include all node_modules etc externals: [ /node_modules/, nodeExternals({ whitelist: [/^@agm/core/, /^hammerjs/], }), ], output: { // Puts the output at the root of the dist folder path: path.join(__dirname, "dist"), filename: "[name].js", }, module: { rules: [ { test: /.ts$/, loader: "ts-loader" }, { // Mark files inside `@angular/core` as using SystemJS style dynamic imports. // Removing this will cause deprecation warnings to appear. test: /[/]@angular[/]core[/].+.js$/, parser: { system: true }, }, ], }, plugins: [ new webpack.ContextReplacementPlugin( // fixes WARNING Critical dependency: the request of a dependency is an expression /(.+)?angular(|/)core(.+)?/, path.join(__dirname, "src"), // location of your src {} // a map of your routes ), new webpack.ContextReplacementPlugin( // fixes WARNING Critical dependency: the request of a dependency is an expression /(.+)?express(|/)(.+)?/, path.join(__dirname, "src"), {} ), ], }; |
اسکریپت های لازم
به منظور هندل کردن Angular Universal در برنامه خود، کدهای زیر را به فایل package.json اضافه کنید.
1 2 3 4 | "build:client-and-server-bundles": "ng build --prod && ng run project-name:server:production", "webpack:server": "webpack --config webpack.server.config.js --progress --colors", "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server", "serve:ssr": "node dist/server" |
تغییر فایل angular.json
آخرین مرحله تغییر در فایل angular.json است. کدهای زیر را کپی کرده و اسم پروژه خود را با project-name عوض کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "project-name": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", "schematics": { "@schematics/angular:component": { "styleext": "scss" } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/browser", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "assets": [ "src/favicon.ico", "src/assets" ], "styles": [ "src/styles.scss" ], "scripts": [] }, "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "project-name:build" }, "configurations": { "production": { "browserTarget": "project-name:build:production" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "project-name:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", "styles": [ "src/styles.scss" ], "scripts": [], "assets": [ "src/favicon.ico", "src/assets" ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "exclude": [ "**/node_modules/**" ] } }, "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/server", "main": "src/main.server.ts", "tsConfig": "src/tsconfig.server.json" }, "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ] } } } } }, "project-name-e2e": { "root": "e2e/", "projectType": "application", "architect": { "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "project-name:serve" } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "**/node_modules/**" ] } } } } }, "defaultProject": "project-name" } |
تست پروژه
حال اگر مراحل فوق را به درستی انجام داده باشید، می توانید با استفاده از دستور زیر پروژه خود را تست کنید.
1 | npm run build:ssr && npm run serve:ssr |
هیچ نظری ثبت نشده است