Chuyển đổi phản ứng thành html tĩnh
Có nhiều lý do khác nhau cho việc này. Một mặt, React tạo ra các thành phần mà không cần nhiều nghi lễ và thỏa hiệp. Mô hình này cũng khá độc lập với React. Với nhà máy JSX mới, bạn thậm chí sẽ không thấy việc nhập React trong TypeScript hoặc Babel Show
Rõ ràng, phải có một lưu ý khi xây dựng mọi ứng dụng giao diện người dùng độc quyền trong React. Bên cạnh cuộc thảo luận tôn giáo rõ ràng về việc liệu React có thực sự là cách phù hợp để làm giao diện người dùng hay không, con voi trong phòng là React… sau tất cả… chỉ là JavaScript Đó là một thư viện JavaScript và nó yêu cầu JavaScript để chạy. Điều này có nghĩa là thời gian tải xuống lâu hơn, trang cồng kềnh hơn và có lẽ là xếp hạng SEO không tốt lắm Tùy chọn sử dụng React không có JavaScriptVậy chúng ta có thể làm gì để cải thiện tình hình?
Có thể bạn có xu hướng xác định với một trong những. Cá nhân, tùy thuộc vào vấn đề, tôi sẽ chọn một trong hai cái sau. Chắc chắn, tôi đã thực hiện khá nhiều thao tác kết xuất phía máy chủ (SSR) với React, nhưng tôi thường thấy rằng sự phức tạp bổ sung không đáng để nỗ lực Tương tự như vậy, tôi có thể là một trong số ít người thực sự không thích Gatsby. Đối với tôi, ít nhất, nó phức tạp hóa hầu hết mọi thứ và tôi không thấy nhiều lợi ích Vì vậy, đây là nó? . Nếu chúng tôi đặt ứng dụng của mình trên một kiến trúc vững chắc, chúng tôi có thể chỉ cần viết một tập lệnh nhỏ và thực sự tự mình thực hiện tạo trang tĩnh (SSG) — không cần Gatsby hay bất kỳ thứ gì khác. Điều này sẽ không phức tạp; Bây giờ chúng ta đang thực sự mong đợi điều gì ở đây? Đặt đúng kỳ vọngTrong bài đăng này, chúng tôi sẽ xây dựng một giải pháp đơn giản để chuyển đổi trang của chúng tôi được tạo bằng React thành một tập hợp các trang web tĩnh được tạo trước đầy đủ. Chúng tôi vẫn có thể hydrat hóa thứ này và để trang web của chúng tôi hoạt động Mục tiêu của chúng tôi là cải thiện hiệu suất kết xuất ban đầu. Trong thử nghiệm Ngọn hải đăng của chúng tôi, chúng tôi thấy rằng trang chủ của chúng tôi không phải lúc nào cũng được nhận thức tốt như chúng tôi mong đợi Hơn 200 nghìn nhà phát triển sử dụng LogRocket để tạo ra trải nghiệm kỹ thuật số tốt hơnTìm hiểu thêm →Những gì chúng tôi sẽ không làm là tối ưu hóa các trang tĩnh để chúng chỉ có các đoạn JavaScript nhỏ. Chúng tôi sẽ luôn cấp nước cho trang bằng JavaScript đầy đủ (có thể vẫn tải chậm, nhưng sẽ bổ sung thêm về điều đó sau) Mặc dù kết xuất trước tĩnh của SPA có thể có lợi cho hiệu suất nhận thức, nhưng chúng tôi sẽ không tập trung vào tối ưu hóa hiệu suất. Nếu bạn quan tâm đến việc tối ưu hóa hiệu suất, bạn nên xem hướng dẫn chuyên sâu này để tối ưu hóa hiệu suất với webpack Một ứng dụng React cơ bảnĐể chuẩn bị cho bài viết này, chúng tôi sử dụng một loại ứng dụng React khá đơn giản nhưng khá phổ biến. Chúng tôi cài đặt một loạt các phụ thuộc dành cho nhà phát triển (vâng, chúng tôi sẽ sử dụng TypeScript cho mục đích dịch mã) npm i webpack webpack-dev-server webpack-cli typescript ts-loader file-loader html-webpack-plugin @types/react @types/react-dom @types/react-router @types/react-router-dom --save-dev Và, tất nhiên, một số phụ thuộc thời gian chạy npm i react react-dom react-router-dom react-router --save Bây giờ chúng tôi thiết lập một module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };6 thích hợp để đóng gói ứng dụng module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, }; Điều này sẽ hỗ trợ TypeScript và các tệp dưới dạng nội dung. Lưu ý rằng đối với một ứng dụng web lớn hơn, chúng tôi có thể cần nhiều thứ khác, nhưng điều này là đủ cho bản demo của chúng tôi Chúng tôi cũng nên thêm một số trang có một chút nội dung để thấy điều này hiệu quả. Trong cấu trúc của chúng tôi, chúng tôi sẽ sử dụng tệp module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };7 để tổng hợp mọi thứ. Tập tin này có thể đơn giản như import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => ( Vấn đề với phương pháp này là chúng tôi sẽ cần chỉnh sửa tệp này cho mỗi trang mới. Nếu chúng ta sử dụng quy ước lưu trữ các trang trong thư mục module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };8, chúng ta có thể nghĩ ra thứ gì đó tốt hơn. Chúng tôi có hai lựa chọn
Cách tiếp cận thứ hai mang lại lợi thế lớn là các tuyến đường có thể là một phần của trang. Đối với phương pháp này, chúng tôi sẽ cần một trình tải webpack khác ________số 8_______Điều này bây giờ cho phép chúng tôi cấu trúc lại tệp module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };7 để trông giống như import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => ( Bây giờ tất cả các trang được xác định đầy đủ bởi import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (1, đây là một mô-đun được tạo nhanh chóng trong quá trình đóng gói. Ngoài ra, chúng tôi đã thêm một thành phần import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (2 để cung cấp cho các trang của chúng tôi một chút cấu trúc được chia sẻ Trình tạo mã cho mô-đun import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (3 trông như thế này const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; }; Chúng tôi chỉ lặp lại trên tất cả các trang và tạo một mô-đun mới, xuất một mảng các đối tượng có thuộc tính import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (4 và import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (5 Tại thời điểm này, mục tiêu của chúng tôi là kết xuất trước ứng dụng đơn giản (nhưng hoàn chỉnh) này Khái niệm cơ bản về SSG với ReactNếu bạn biết SSR với React, bạn đã biết mọi thứ bạn cần để thực hiện một số SSG cơ bản. Về cốt lõi, chúng tôi sử dụng hàm import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (6 từ import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (7 thay vì import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (8 từ import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (9. Giả sử chúng ta có một trang được lồng trong một bố cục, đoạn mã sau có thể hoạt động rồi const element = ( Trong đoạn mã trên, chúng tôi giả sử rằng bố cục được cung cấp đầy đủ trong thành phần import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (2. Chúng tôi cũng giả định rằng React Router được sử dụng để định tuyến phía máy khách. Do đó, chúng ta cần cung cấp ngữ cảnh định tuyến thích hợp. May mắn thay, việc chúng ta sử dụng npm i parcel-codegen-loader --save-dev1, npm i parcel-codegen-loader --save-dev2 hay npm i parcel-codegen-loader --save-dev3 không thực sự quan trọng — tất cả đều cung cấp ngữ cảnh định tuyến Các bài viết hay khác từ LogRocket
Bây giờ, npm i parcel-codegen-loader --save-dev4 là gì? . Bạn có thể có nhiều thành phần hơn mà bạn muốn đưa vào trên mỗi trang. Một ví dụ điển hình sẽ là thành phần npm i parcel-codegen-loader --save-dev6, thường được tích hợp như Nhưng đây sẽ là một thành phần mà chúng tôi sẽ để lại cho quá trình hydrat hóa khi trang tĩnh của chúng tôi trở nên động. Không cần kết xuất trước Mặt khác, bản thân ứng dụng thường trông giống như const app = ( Điều này khá gần với đoạn trích để tạo tĩnh. Sự khác biệt chính là ở đây chúng tôi bao gồm tất cả các trang (và hydrat hóa), trong khi ở kịch bản SSG ở trên, chúng tôi giảm toàn bộ nội dung trang thành một trang cố định Cạm bẫy của SSGChà, cho đến nay mọi thứ nghe có vẻ đơn giản và dễ dàng, phải không? Hỗ trợ tài sảnLàm thế nào để chúng ta đề cập đến tài sản? npm i react react-dom react-router-dom react-router --save0 Điều này có thể hoạt động nếu npm i parcel-codegen-loader --save-dev7 tồn tại trên máy chủ của chúng tôi. Sử dụng URL đầy đủ sẽ đáng tin cậy hơn một chút, e. g. , npm i parcel-codegen-loader --save-dev8. Tuy nhiên, sau đó chúng tôi sẽ từ bỏ một số tính linh hoạt liên quan đến môi trường Khá thường xuyên, dù sao thì chúng tôi cũng để lại những nội dung đó cho các gói như webpack. Trong trường hợp này, chúng tôi có mã như npm i react react-dom react-router-dom react-router --save1 Ở đây, npm i parcel-codegen-loader --save-dev7 được giải quyết cục bộ tại thời điểm xây dựng, sau đó được băm, tối ưu hóa và sao chép vào thư mục đích. Tất cả đều ổn. Tuy nhiên, đối với quy trình được mô tả ở trên, chỉ yêu cầu mô-đun trong Nút. js sẽ không hoạt động. Chúng tôi sẽ đánh một ngoại lệ rằng npm i parcel-codegen-loader --save-dev7 không phải là một mô-đun hợp lệ Giải quyết vấn đề này thực ra không phức tạp. May mắn thay, chúng ta có thể đăng ký các tiện ích mở rộng bổ sung cho các mô-đun trong Node. js npm i react react-dom react-router-dom react-router --save2 Đoạn mã trên giả định rằng tệp đã/sẽ được sao chép vào thư mục gốc. Vì vậy, chúng tôi sẽ biến đổi import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (1 thành import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (2 Còn phần băm thì sao? npm i react react-dom react-router-dom react-router --save3 Điều này sẽ cố gắng tìm một tệp bắt đầu bằng “foo” và kết thúc bằng “png”, chẳng hạn như import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (3. Nghỉ ngơi như trên Hỗ trợ TypeScriptBây giờ chúng tôi đã biết cách xử lý nội dung chung, chúng tôi cũng có thể cung cấp cơ chế xử lý cho các tệp import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (4 và import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (5. Rốt cuộc, những thứ này cũng có thể được dịch sang JS trong bộ nhớ. Tuy nhiên, tất cả công việc này là hoàn toàn không cần thiết, vì import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (6 đã làm việc đó rồi. Vì vậy, công việc của chúng tôi về cơ bản giảm xuống npm i react react-dom react-router-dom react-router --save4 Sau đó đăng ký trình xử lý cho các phần mở rộng tệp tương ứng bằng cách sử dụng npm i react react-dom react-router-dom react-router --save5 Bây giờ, điều này cho phép chỉ yêu cầu các mô-đun được xác định là tệp import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (5 tải chậmNếu chúng tôi đã viết một React SPA được tối ưu hóa, thì chúng tôi cũng sẽ chia nhóm ứng dụng của mình ở cấp định tuyến. Điều này có nghĩa là mỗi trang đều có gói phụ của riêng mình. Như vậy, sẽ có một gói lõi/chung (thường chứa cơ chế định tuyến, chính React, một số phụ thuộc được chia sẻ, v.v. ) và một gói cho mỗi trang. Nếu chúng tôi có 10 trang, chúng tôi sẽ có 11 (hoặc nhiều hơn) gói Nhưng sử dụng phương pháp kết xuất trước, điều này không lý tưởng lắm. Rốt cuộc, chúng tôi đã kết xuất trước các trang riêng lẻ. Điều gì sẽ xảy ra nếu chúng ta có một thành phần phụ trên một trang (e. g. , một điều khiển bản đồ) sẽ được chia sẻ, nhưng quá lớn nên chúng tôi muốn đưa nó vào gói riêng? Đó là, chúng ta có một thành phần như npm i react react-dom react-router-dom react-router --save6 Trường hợp thành phần thực tế sẽ được tải chậm. Trong kịch bản này, chúng tôi sẽ đụng phải một bức tường khá mạnh. React không biết cách kết xuất trước import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (8 May mắn thay, chúng ta có thể định nghĩa lại import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (8 để chỉ hiển thị một số trình giữ chỗ (chúng ta cũng có thể phát điên ở đây và thực sự tải hoặc hiển thị trước nội dung, nhưng hãy giữ cho nó đơn giản và giả sử rằng bất kỳ thứ gì được tải chậm ở đây thực sự sẽ được tải chậm sau này npm i react react-dom react-router-dom react-router --save7 Phần khác không có sẵn để sử dụng trong import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; const HomePage = React.lazy(() => import('./pages/home')); const FirstPage = React.lazy(() => import('./pages/first')); const NotFoundPage = React.lazy(() => import('./pages/not-found')); const App = () => (6 là const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };1. Chà, thành thật mà nói, việc thực hiện điều này sẽ không gây hại gì, nhưng chúng ta hãy tự làm điều đó Tất cả những gì chúng ta cần làm ở đây là hành động như thể const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };1 hoàn toàn không có ở đó. Vì vậy, chúng tôi chỉ cần thay thế nó bằng một đoạn bằng cách sử dụng const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };3 được cung cấp npm i react react-dom react-router-dom react-router --save8 Bây giờ chúng tôi xử lý lazy loading khá hiệu quả, mặc dù, tùy thuộc vào tình huống, chúng tôi có thể (và thậm chí có thể muốn) làm nhiều hơn thế Những thứ khácBên cạnh những thứ như import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (8 và const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };1, các phần khác cũng có thể bị thiếu trong React. Một ví dụ điển hình là const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };6. Tuy nhiên, vì const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };6 thường chỉ áp dụng trong thời gian chạy, nên cách dễ dàng để hỗ trợ nó là tránh nó hoàn toàn Cách thực hiện khá đơn giản là thay thế nó bằng chức năng không hoạt động. Bằng cách này, const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };6 không cản trở chúng ta và đơn giản là bị bỏ qua npm i react react-dom react-router-dom react-router --save9 Một số mô-đun chúng tôi const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };9 thực sự sẽ không ở định dạng CommonJS. Đây là một vấn đề lớn. Tại thời điểm viết bài, Nút. js chỉ hỗ trợ các mô-đun CommonJS (các mô-đun ES vẫn đang thử nghiệm) May mắn thay, có , cung cấp cho chúng tôi hỗ trợ cho các mô-đun ES bằng cách sử dụng các câu lệnh const element = (0 và const element = (1. Tuyệt vời Giống như với import * as React from 'react'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { render } from 'react-dom'; import Layout from './Layout'; const pages = require('./toc.codegen'); const [notFound] = pages.filter((m) => m.route === '*'); const standardPages = pages.filter((m) => m !== notFound); const App = () => (6, chúng tôi sẽ bắt đầu bằng cách cài đặt phần phụ thuộc module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };0 Và sau đó thực sự sử dụng nó. Trong trường hợp này, chúng ta cần thay thế const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };9 “bình thường” bằng một phiên bản mới của nó. mã đọc module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };1 Bây giờ chúng tôi cũng có hỗ trợ cho các mô-đun ES. Điều duy nhất còn thiếu có thể là một số chức năng liên quan đến DOM Mặc dù thông thường chúng ta nên đặt các điều kiện trong mã của mình như vậy module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };2 Chúng ta cũng có thể làm giả một số quả địa cầu khác. Chẳng hạn, chúng tôi (hoặc một số người phụ thuộc mà chúng tôi sử dụng trực tiếp hoặc gián tiếp) có thể đề cập đến const element = (4, const element = (5 hoặc const element = (6. Trong những trường hợp này, chúng ta có thể chế nhạo chúng bằng cách mở rộng đối tượng const element = (7 Với cùng một logic, chúng ta có thể chế nhạo const element = (8, hoặc ít nhất là một phần của nó. Tất nhiên, có gói const element = (9, giúp với hầu hết chúng rồi. Nhưng bây giờ hãy giữ cho nó đơn giản và đi vào vấn đề Chỉ là một ví dụ chế giễu module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };3 Bây giờ chúng tôi có mọi thứ để bắt đầu kết xuất trước ứng dụng của mình mà không gặp nhiều khó khăn Mang tất cả lại với nhauCó nhiều cách chúng ta có thể khái quát hóa và sử dụng các đoạn trích trên. Cá nhân tôi thích sử dụng chúng trong một mô-đun riêng biệt, được đánh giá/sử dụng trên mỗi trang bằng cách sử dụng 0. Bằng cách này, chúng tôi luôn nhận được các quy trình biệt lập, cũng có thể được xử lý song song Một triển khai ví dụ được hiển thị bên dưới module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };4 Việc triển khai này có thể được sử dụng như một lib cũng như trực tiếp thông qua 1. Đó là lý do tại sao chúng tôi phân biệt giữa hai trường hợp bằng cách sử dụng 2 làm phân biệt đối xử. Trường hợp là lib thì ta export 2 hàm 3 và 4 Điều duy nhất còn lại ở đây là định nghĩa của 5. Đối với điều này, chúng tôi chỉ có thể sử dụng định nghĩa mà chúng tôi đã chỉ định trong phần giới thiệu về ứng dụng React cơ bản Mô-đun 6 sẽ chứa mã ở trên. Được bọc trong một phong bì thích hợp để sử dụng trong quy trình rẽ nhánh, chúng tôi kết thúc với module.exports = { mode: 'production', devtool: 'source-map', entry: './src/index.tsx', output: { filename: 'app.js', }, resolve: { extensions: ['.ts', '.tsx', '.js'], }, module: { rules: [ { test: /\.tsx?$/, loader: 'ts-loader' }, { test: /\.(png|jpe?g|gif)$/i, loader: 'file-loader' }, ], }, };5 Trong đó 7 sẽ thiết lập các sửa đổi cần thiết cho const { getPages } = require('./helpers'); module.exports = () => { const pageDetails = getPages(); const pages = pageDetails.map((page) => { const meta = [ `"content": lazy(() => import('./${page.folder}/${page.name}'))`, `${JSON.stringify('route')}: ${JSON.stringify(page.route)}`, ]; return `{ ${meta.join(', ')} }`; }); return `const { lazy } = require('react'); module.exports = [${pages.join(', ')}];`; };9, trong khi 9 thực hiện tạo đánh dấu thực tế. const app = (0 sử dụng đầu ra từ 9 để thực sự viết ra trang được tạo Sử dụng thiết lập như vậy, chúng tôi có thể kết xuất trước trang web của mình và tăng hiệu suất đáng kể, như được xác nhận bởi Lighthouse Như một tác dụng phụ thú vị, trang web của chúng tôi hiện cũng hoạt động — ở một mức độ nào đó — cho người dùng không có JavaScript. Ứng dụng ví dụ đầy đủ có thể được tìm thấy trên GitHub Phần kết luậnSử dụng React để tạo các trang tĩnh tuyệt vời thực sự không phải là vấn đề lớn. Không cần phải quay trở lại các khuôn khổ cồng kềnh và phức tạp. Bằng cách này, chúng ta có thể kiểm soát rất tốt những gì cần nhập và những gì cần loại bỏ. Ngoài ra, chúng tôi tìm hiểu khá nhiều về nội bộ của Node. js, React và có khả năng là một số phần phụ thuộc mà chúng tôi sử dụng. Biết những gì chúng ta thực sự sử dụng không chỉ là một bài tập học thuật mà còn rất quan trọng trong trường hợp có lỗi hoặc các vấn đề khác Hiệu suất đạt được khi kết xuất trước một SPA với kỹ thuật này có thể rất tốt. Quan trọng hơn, trang của chúng tôi trở nên dễ truy cập hơn và được xếp hạng cao hơn cho mục đích SEO Bạn thấy kết xuất trước tỏa sáng ở đâu? Tôi có thể chuyển đổi React sang HTML không?Có, cả ứng dụng Angular và React đều có thể (và thường được) "xây dựng" thành HTML, CSS và JS tĩnh .
Cách sử dụng tĩnh trong HTML React?Tạo Thành phần phản ứng trong chỉ mục. jsx , sau đó sao chép và dán phần nội dung của tệp HTML tĩnh của bạn vào câu lệnh trả về của Thành phần đó . Và nếu bạn có nhiều trang, tôi khuyên bạn nên tạo một thư mục trang riêng trong thư mục src và tạo. js cho mỗi trang (HTML) của trang web tĩnh của bạn.
Tôi có thể tạo trang web tĩnh bằng React không?Đó là lý do tại sao ngày nay, nó cũng thường được sử dụng cho các trang web tĩnh. Khả năng kích hoạt các tệp HTML dựng sẵn giúp tăng tốc độ tải của React khiến nó trở thành một khung hoàn hảo để xây dựng SSG . React cho phép tiếp cận chi tiết trong việc thực hiện các thay đổi đối với trang web tĩnh của bạn bằng cách chỉ có thể chỉnh sửa một tệp thành phần.
Lệnh nào được sử dụng để chuyển đổi dự án React thành các tệp CSS & js HTML tĩnh?Chạy npm build hoặc yarn build , thao tác này sẽ tạo thư mục bản dựng, trong đó bạn có thư mục tĩnh, chỉ mục. html, tất cả các tệp css, js của bạn, tất cả đã được rút gọn, sẵn sàng để triển khai. |