CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.
Bài viết blog CFSDN này nói về các tính năng out-of-box của Nuxt, được tác giả sưu tầm và biên soạn. Nếu bạn quan tâm đến bài viết này thì nhớ like nhé.

trích dẫn
Gần đây Nuxt framework được sử dụng trong các dự án của hãng để thực hiện render màn hình đầu tiên phía server, đẩy nhanh tốc độ time-to-content nên tác giả bắt đầu tìm hiểu và sử dụng Nuxt. Sau đây là phần giới thiệu và phân tích một số tính năng của Nuxt từ góc độ mã nguồn.
ĐẶC TRƯNG
Kết xuất phía máy chủ (SSR)
Vue.js là một framework để xây dựng các ứng dụng phía máy khách. Theo mặc định, các thành phần Vue có thể được xuất ra trong trình duyệt để tạo DOM và vận hành DOM. Tuy nhiên, cũng có thể hiển thị các thành phần tương tự như chuỗi HTML phía máy chủ, gửi chúng trực tiếp đến trình duyệt và cuối cùng "kích hoạt" các thẻ tĩnh này thành một ứng dụng tương tác đầy đủ trên máy khách. ------Hướng dẫn Vue SSR.
Chương sử dụng cơ bản của hướng dẫn Vue SSR chính thức cung cấp cách triển khai kết xuất phía máy chủ ở cấp độ demo cũng được triển khai dựa trên chương này và quy trình chung gần như giống nhau. Bạn nên đọc hướng dẫn chính thức trước rồi đọc bài viết này, điều này sẽ mang lại lợi ích rất lớn.
Là một khung kết xuất phía máy chủ, Nuxt phải được ưu tiên hàng đầu để hiểu các nguyên tắc triển khai kết xuất phía máy chủ. Chúng ta hãy xem xét cách triển khai cụ thể của nó thông qua mã nguồn có liên quan.
Chúng tôi khởi động dự án Nuxt thông qua nuxt. Đầu tiên, nó sẽ thực thi phương thức startDev, sau đó gọi phương thức _listenDev để lấy cấu hình Nuxt và gọi phương thức getNuxt để khởi tạo Nuxt. Sau đó thực thi phương thức nuxt.ready() để tạo trình kết xuất.
- // @nuxt/máy chủ/src/máy chủ.js
- sẵn sàng bất đồng bộ () {
- // Khởi tạo vue-renderer
- this.serverContext = new ServerContext(này)
- this.renderer = new VueRenderer(this.serverContext)
- chờ đợi this.renderer.ready()
-
- // Thiết lập phần mềm trung gian nuxt
- chờ đợi this.setupMiddleware()
-
- trở lại cái này
- }
This.setupMiddleware() sẽ được thực thi ở trạng thái sẵn sàng, nó sẽ gọi phần mềm trung gian nuxtMiddleware (đây là chìa khóa cho phản hồi).
- // @nuxt/máy chủ/src/phần mềm trung gian/nuxt.js
- xuất khẩu mặc định ({tùy chọn, nuxt, renderRoute, tài nguyên }) => async chức năng nuxtMiddleware (yêu cầu, res, Kế tiếp) {
- const context = getContext(req, res)
- thử {
- const url = chuẩn hóaURL(req.url)
- res.statusCode = 200
- const result = chờ đợi renderRoute(url, context) // Hiển thị tuyến đường tương ứng, tuyến đường này sẽ được mở rộng sau.
-
- hằng số {
- html,
- được chuyển hướng,
- Tải trước các tập tin
- } = kết quả // lấy html
-
- //Đặt trường tiêu đề
- res.setHeader('Loại nội dung', 'text/html; charset=utf-8')
- res.setHeader('Phạm vi chấp nhận', 'không có')
- res.setHeader('Độ dài nội dung', Bộ đệm. byteLength(html))
- độ phân giảikết thúc(html, 'utf8') // trả lời
- trở lại html
- } bắt (err) {
- nếu (bối cảnh && bối cảnh.được chuyển hướng) {
- console.error(err)
- trở lại lỗi
- }
- Kế tiếp(lầm)
- }
- }
Phần mềm trung gian nuxtMiddleware trước tiên chuẩn hóa URL được yêu cầu, đặt mã trạng thái yêu cầu, khớp tuyến đường tương ứng thông qua URL, hiển thị thành phần định tuyến tương ứng, đặt thông tin tiêu đề và cuối cùng phản hồi.
- renderSSR (renderContext) {
- // Gọi renderToString từ bóRenderer Và tạo ra HTML (sẽ cập nhật renderContext BẰNG Tốt)
- // renderSSR chỉ là phương thức kết xuất của ứng dụng phổ quát Nuxt cũng có thể phát triển các dự án SPA thông thường.
- const renderer = renderContext.modern ? this.renderer.modern : this.renderer.SSR
- trở lại render.render(renderContext)
- }
Phương thức renderRoute sẽ gọi renderSSR của @nuxt/vue-render để thực hiện các hoạt động kết xuất phía máy chủ.
- // @nuxt/vue-renderer/src/renderers/SSR.js
- kết xuất không đồng bộ (renderContext) {
- // Gọi trình kết xuất Vue renderToString
- hãy để APP = chờ this.vueRenderer.renderToString(renderContext)
-
- hãy để HEAD = ''
- // ... n dòng mã ghép HEAD bị bỏ qua ở đây, phần này sẽ được đề cập trong phần quản lý HEAD tiếp theo.
-
- // Kết xuất với Mẫu SSR
- const html = this.renderTemplate(this.serverContext.resources.SSRTemplate, templateParams)
-
- trở lại {
- html,
- Tải trước các tập tin
- }
- }
renderSSR sẽ gọi phương thức renderer.render để hiển thị tuyến đường khớp với url thành một chuỗi, kết hợp chuỗi đó với mẫu và lấy html cuối cùng được trả về trình duyệt. Tại thời điểm này, quá trình hiển thị phía máy chủ Nuxt đã hoàn tất. .
Cuối cùng, tôi đăng biểu đồ luồng thực thi Nuxt bị đánh cắp. Hình ảnh rất đẹp và quy trình rất rõ ràng. Cảm ơn bạn.

Tìm nạp dữ liệu
Trong chương trình máy khách (CSR), dữ liệu có thể được lấy thông qua hook được gắn, nhưng trong chương trình phổ quát (Universal), cần có một hook cụ thể để lấy dữ liệu ở phía máy chủ.
Nuxt chủ yếu cung cấp hai hook để lấy dữ liệu.
- không đồng bộDữ liệu
- Nó chỉ có thể được lấy từ các thành phần cấp trang và không thể truy cập được.
- Lưu trạng thái dữ liệu bằng cách trả về đối tượng hoặc hợp tác với Vuex để lưu trạng thái
- tìm về
- Nó có sẵn trong tất cả các thành phần và có thể truy cập vào đây
- Không cần phải chuyển theo ngữ cảnh. Việc chuyển theo ngữ cảnh sẽ chuyển sang phiên bản tìm nạp cũ và chức năng của nó tương tự như asyncData.
- // .nuxt/máy chủ.js
- // Các thành phần đã được giải quyết qua setContext -> getRouteData (ứng dụng/utils.js)
- const Components = getMatchedComponents(app.context.route)
-
- // Trong lộ trình phù hợp, hãy gọi asyncData và phiên bản kế thừa tìm vềphương pháp
- const asyncDatas = await Lời hứa.tất cả(Components.map((Thành phần) => {
- const lời hứa = []
-
- // Gọi asyncData(context)
- nếu (Component.options.asyncData && typeof Component.options.asyncData === 'chức năng') {
- const promise = promisify(Component.options.asyncData, app.context)
- hứa.sau đó((asyncDataResult) => {
- SSRContext.asyncData[Thành phần.cid] = asyncDataResult
- áp dụngAsyncData(Thành phần)
- trở lại asyncDataKết quả
- })
- lời hứa.push(lời hứa)
- } khác {
- lời hứa.đẩy(vô giá trị)
- }
-
- // Gọi phiên bản kế thừatìm về(ngữ cảnh) Tương thích với các phiên bản cũ hơn tìm về
- nếu (Component.options.tìm về && Tùy chọn thành phần.tìm về.chiều dài) {
- promises.push(Component.options.tìm về(ứng dụng.bối cảnh))
- } khác {
- lời hứa.đẩy(vô giá trị)
- }
-
- trở lại Hứa.tất cả(hứa hẹn)
- }))
Trong .nuxt/server.js được tạo, các thành phần phù hợp sẽ được duyệt qua để kiểm tra xem tùy chọn asyncData và phiên bản tìm nạp cũ có được xác định trong thành phần hay không. Nếu chúng tồn tại, chúng sẽ được gọi theo trình tự để lấy asyncDatas.
- // .nuxt/mixins/tìm về.server.js
- // nuxt v2.14 trở lên
- không đồng bộ chức năng máy chủ tải trước() {
- // Gọi Và chờ đợi TRÊN $tìm về
- // Được khuyến nghị sau v2.14 tìm về
- thử {
- chờ đợi điều này.$options.tìm về.gọi(cái này)
- } bắt (err) {
- nếu (process.dev) {
- console. lỗi('Lỗi trong fetch():', lỗi)
- }
- }
- cái này.$fetchState.pending = SAI // Đặt trạng thái tìm nạp thành SAI
- }
Sau khi phiên bản vue được khởi tạo ở phía máy chủ, serverPrefetch được thực thi, phương thức tùy chọn tìm nạp được kích hoạt và dữ liệu sẽ được sử dụng trong quá trình tạo HTML.
Quản lý HEAD (Thẻ meta và SEO)
Hiện tại, Google và Bing lập chỉ mục các ứng dụng JavaScript đồng bộ rất tốt. Tuy nhiên, đối với các trang web lấy dữ liệu không đồng bộ, các công cụ tìm kiếm chính thống vẫn chưa thể hỗ trợ, dẫn đến thứ hạng tìm kiếm của trang web bị thấp. Do đó, hy vọng đạt được SEO tốt hơn đã trở thành lý do khiến nhiều trang web cân nhắc sử dụng khung SSR.
Để có được SEO tốt, cần phải tiến hành cấu hình và quản lý HEAD tinh tế. Hãy xem nó được thực hiện như thế nào nhé~.
Khung Nuxt sử dụng thư viện vue-meta để tùy chỉnh các thẻ meta trang chung và riêng lẻ. Việc triển khai nội bộ của Nuxt gần như tuân theo quy trình quản lý meta SSR chính thức của vue-meta. Vui lòng kiểm tra để biết chi tiết cụ thể.
- // @nuxt/vue-app/template/chỉ số.js
- // bước 1
- Vue.use(Meta, JSON.stringify(vueMetaOptions))
-
- // @nuxt/vue-app/template/template.js
- // bước 2
- xuất khẩu mặc định không đồng bộ (SSRContext) => {
- const _app = new Vue(ứng dụng)
- // Thêm vào thông tin meta (đã sử dụng TRONG renderer.js)
- SSRContext.meta = _app.$meta()
- trở lại _ứng dụng
- }
Đầu tiên, hãy đăng ký vue-meta dưới dạng một plug-in Vue và thuộc tính $meta sẽ được gắn bên trong trên nguyên mẫu Vue. Sau đó thêm meta vào ngữ cảnh hiển thị phía máy chủ.
- kết xuất không đồng bộ (renderContext) {
- // Gọi trình kết xuất Vue renderToString
- hãy để APP = chờ this.vueRenderer.renderToString(renderContext)
- // bước 3
- hãy để HEAD = ''
-
- // Tiêm meta đầu
- // (cái này là bỏ đặt khi tính năng.meta là SAI TRONG mẫu máy chủ)
- // Sau đây là n dòng mã ghép HEAD bị bỏ qua ở trên, có thể bỏ qua một cách thích hợp.
- // Chỉ cần hiểu quy trình chính, kiểm tra các chi tiết cụ thể khi cần thiết
- hằng số meta = renderContext.meta && renderContext.meta.inject({
- isSSR: renderContext.nuxt.serverRendered,
- ln: this.options.dev
- })
-
- nếu (siêu) {
- ĐẦU += meta.title.text() + meta.meta.text()
- }
-
- nếu (siêu) {
- ĐẦU += meta.link.text() +
- meta.style.text() +
- meta.script.text() +
- meta.noscript.text()
- }
-
- // Kiểm tra nếu chúng ta cần ĐẾN tiêm tập lệnh Và tình trạng
- const shouldInjectScripts = this.options.render.injectScripts !== SAI
-
- // Chèn gợi ý tài nguyên
- nếu (this.options.render.resourceHints && shouldInjectScripts) {
- HEAD += this.renderResourceHints(renderContext)
- }
-
- // Tiêm các kiểu
- HEAD += this.renderStyles(renderContext)
-
-
- // Thêm các tập lệnh vào trước
- nếu (shouldInjectScripts) {
- ỨNG DỤNG += this.renderScripts(renderContext)
- }
-
- nếu (siêu) {
- const appendInjectorOptions = { thân: ĐÚNG VẬY }
- // Thêm các tập lệnh thân bài
- ỨNG DỤNG += meta.meta.text(appendInjectorOptions)
- ỨNG DỤNG += meta.link.text(appendInjectorOptions)
- ỨNG DỤNG += meta.style.text(appendInjectorOptions)
- ỨNG DỤNG += meta.script.text(appendInjectorOptions)
- ỨNG DỤNG += meta.noscript.text(appendInjectorOptions)
- }
-
- // Tham số mẫu
- hằng số mẫuParams = {
- HTML_ATTRS: meta ? meta.htmlAttrs.text(renderContext.nuxt.serverRendered /* addSrrAttribute */) : '',
- HEAD_ATTRS: meta ? meta.headAttrs.text() : '',
- BODY_ATTRS: meta ? meta.bodyAttrs.text() : '',
- CÁI ĐẦU,
- ỨNG DỤNG,
- ENV: tùy chọn này.env
- }
-
- // Kết xuất với Mẫu SSR
- // Tạo html thông qua các mẫu và tham số
- const html = this.renderTemplate(this.serverContext.resources.SSRTemplate, templateParams)
-
- hãy tải trước các tập tin
- nếu (this.options.render.http2.push) {
- // Lấy các file cần tải trước
- preloadFiles = this.getPreloadFiles(renderContext)
- }
-
- trở lại {
- html,
- tải trước các tập tin,
- }
- }
Cuối cùng, đưa siêu dữ liệu vào html phản hồi.
Định tuyến hệ thống tệp
Những sinh viên đã sử dụng Nuxt chắc chắn sẽ bị ấn tượng bởi tính năng tạo tuyến đường dựa trên các tệp. Hãy để tôi xem cách Nuxt triển khai việc tạo tuyến đường tự động dựa trên thư mục trang (có thể định cấu hình) từ góc độ mã nguồn.
Đầu tiên, khi bắt đầu dự án Nuxt hoặc sửa đổi tệp, phương thức generateRoutesAndFiles sẽ tự động được gọi để tạo các tuyến và tệp trong thư mục .nuxt.
- // @nuxt/builder/src/builder.js
- không đồng bộ generateRoutesAndFiles() {
- ...
- chờ đợi Lời hứa.tất cả([
- này.resolveLayouts(templateContext),
- this.resolveRoutes(templateContext), //Giải quyết và tạo các tuyến đường, những điểm chính cần chú ý
- this.resolveStore(templateContext),
- this.resolveMiddleware(templateContext)
- ])
- ...
- }
Có ba tình huống khi phân tích các tuyến: thứ nhất, tên thư mục trang mặc định được sửa đổi và thư mục liên quan không được định cấu hình trong nuxt.config.js. Thứ hai, thư mục các trang mặc định của nuxt được sử dụng; thứ ba, các tuyến do người dùng xác định được tạo bằng cách gọi; Phương pháp tạo đường đi.
- // @nuxt/builder/src/builder.js
- bất đồng bộ giải quyết tuyến đường({templateVars}) {
- console.debug('Đang tạo tuyến đường...')
- nếu (this._defaultPage) {
- // Không tìm thấy thư mục trang trong srcDir
- } khác nếu (this._nuxtPage) {
- // Sử dụng nuxt để tạo tuyến đường động
- } khác {
- // Người dùng cung cấp các phương thức tùy chỉnh để tạo tuyến đường và cung cấp cho người dùng khả năng tùy chỉnh tuyến đường.
- }
- // phương thức router.extendRoutes
- nếu (typeof this.options.router.extendRoutes === 'chức năng') {
- const extendedRoutes = chờ tùy chọn này.router.extendRoutes(
- templateVars.router.routes,
- giải quyết
- )
- nếu (extendedRoutes !== không xác định) {
- templateVars.router.routes = mở rộng tuyến đường
- }
- }
- }
Ngoài ra, bạn cũng có thể cung cấp phương thức ExtendRoutes tương ứng để thêm các tuyến tùy chỉnh dựa trên các tuyến được tạo bởi nuxt.
- xuất khẩu mặc định {
- bộ định tuyến: {
- extendRoutes(tuyến đường, giải quyết) {
- // Ví dụ: thêm trang 404
- tuyến đường.đẩy({
- tên: 'phong tục',
- con đường: '*',
- thành phần: giải quyết(__dirname, 'trang/404.view')
- })
- }
- }
- }
Khi thư mục trang mặc định được sửa đổi và không thể tìm thấy thư mục liên quan, tệp @nuxt/vue-app/template/pages/index.vue sẽ được sử dụng để tạo các tuyến đường.
- bất đồng bộ giải quyết tuyến đường({templateVars}) {
- nếu (this._defaultPage) {
- // Phương thức createRoutes tạo các tuyến dựa trên các tham số đã truyền. Thuật toán cụ thể sẽ không được mở rộng.
- templateVars.router.routes = createRoutes({
- tập tin: ['index.view'],
- srcDir: this.template.dir + '/trang', // Trỏ tới @nuxt/vue-app/template/pages/chỉ số.xem
- RouteNameSplitter, // Dấu phân cách tên tuyến, mặc định `-`
- dấu gạch chéo cuối // dấu gạch chéo cuối /
- })
- } khác nếu (this._nuxtPage) {
- các tập tin const = {}
- const ext = new RegExp(`\\.(${this.supportedExtensions.tham gia('|')})$`)
- vì (trang const của đang chờ this.resolveFiles(this.options.dir.pages)) {
- hằng số chìa khóa = trang.thay thế(mở rộng, '')
- // Tệp .vue được ưu tiên hơn các phần mở rộng khác
- nếu (/\.vue$/.test(trang) || !files[chìa khóa]) {
- tập tin[chìa khóa] = trang.thay thế(/(['"])/g, '\\$1')
- }
- }
- templateVars.router.routes = createRoutes({
- tập tin: Đối tượng.giá trị(tập tin),
- srcDir: this.options.srcDir,
- pagesDir: this.options.dir.pages,
- RouteNameSplitter,
- supportedExtensions: this.supportedExtensions,
- dấu gạch chéo theo sau
- })
- } khác {
- templateVars.router.routes = chờ this.options.build.createRoutes(this.options.srcDir)
- }
- // phương thức router.extendRoutes
- nếu (typeof this.options.router.extendRoutes === 'chức năng') {
- const extendedRoutes = chờ tùy chọn này.router.extendRoutes(
- templateVars.router.routes,
- giải quyết
- )
- nếu (extendedRoutes !== không xác định) {
- templateVars.router.routes = mở rộng tuyến đường
- }
- }
- }
Sau đó gọi phương thức createRoutes để tạo tuyến đường. Tuyến đường được tạo trông gần giống như thế này, gần giống với tệp tuyến đường được viết thủ công (nó sẽ được đóng gói và tải từng phần để giới thiệu các thành phần định tuyến sau này).
- [
- {
- tên: 'chỉ số',
- con đường: '/',
- Tên chunk: 'trang/chỉ mục',
- thành phần: 'Người dùng/tên người dùng/tên dự án/trang/index.vue'
- },
- {
- tên: 'Về',
- con đường: '/Về',
- Tên chunk: 'trang/giới thiệu/chỉ mục',
- thành phần: 'Người dùng/tên người dùng/tên dự án/trang/giới thiệu/index.vue'
- }
- ]
Tìm nạp trước thông minh
Bắt đầu từ Nuxt v2.4.0, khi xuất hiện ở vùng hiển thị, Nuxt sẽ tìm nạp trước tập lệnh trang được phân tách mã, để trước khi người dùng nhấp vào, địa chỉ mà tuyến đường trỏ đến sẽ ở trạng thái sẵn sàng, điều này sẽ vô cùng tuyệt vời. cải thiện trải nghiệm người dùng.
Logic triển khai có liên quan tập trung ở .nuxt/comComponents/nuxt-link.client.js.
Trước hết, việc triển khai tính năng Tìm nạp trước thông minh dựa trên cửa sổ API thử nghiệm.IntersectionObserver. Nếu trình duyệt không hỗ trợ API này, thao tác tìm nạp trước thành phần sẽ không được thực hiện.
- gắn kết () {
- nếu (this.prefetch && !this.noPrefetch) {
- this.handleId = requestIdleCallback(this.observe, { thời gian chờ: 2e3 })
- }
- }
Sau đó, trong giai đoạn gắn thành phần cần được tìm nạp trước, phương thức requestIdleCallback được gọi và phương thức quan sát được gọi trong khoảng thời gian không hoạt động của trình duyệt.
- const observer = window.IntersectionObserver && new window.IntersectionObserver((entries) => {
- mục nhập.forEach(({intersectionRatio, mục tiêu: liên kết }) => {
- // Nếu crossoverRatio nhỏ hơn hoặc bằng 0, điều đó có nghĩa là mục tiêu không nằm trong khung nhìn
- nếu (intersectionRatio <= 0 || !link.__prefetch) {
- trở lại
- }
- // Tìm nạp trước dữ liệu (thực chất là tải các thành phần)
- liên kết.__prefetch()
- })
- })
Khi trạng thái trực quan của phần tử được giám sát thay đổi (và xuất hiện trong chế độ xem), lệnh gọi lại của window.IntersectionObserver(callback) mới sẽ được kích hoạt để thực hiện thao tác tìm nạp trước thực tế prefetchLink.
- liên kết nạp trước () {
- // Xác định môi trường mạng Trong môi trường ngoại tuyến hoặc 2G, không có thao tác tìm nạp trước nào được thực hiện.
- nếu (!this.canPrefetch()) {
- trở lại
- }
- // Dừng nghe phần tử này để cải thiện hiệu suất
- observer.unobserve(this.$el)
- const Components = this.getPrefetchComponents()
-
- vì (const Thành phần của Thành phần) {
- //Load thành phần kịp thời để khi người dùng click vào, thành phần đó ở trạng thái sẵn sàng
- const componentOrPromise = Thành phần()
- nếu (componentOrPromise thể hiện của Promise) {
- thành phầnOrPromise.catch(() => {})
- Thành phần.__đã tải trước = ĐÚNG VẬY // Gắn cờ các bit đã được tìm nạp trước
- }
- }
Tóm tắt
Phần trên mô tả cách triển khai kết xuất phía máy chủ Nuxt, thu thập dữ liệu phía máy chủ và một số tính năng sẵn có của Nuxt từ góc độ mã nguồn: quản lý HEAD, định tuyến dựa trên hệ thống tệp và tìm nạp trước thông minh định tuyến chia mã. Nếu bạn muốn tiến hành nghiên cứu chuyên sâu hơn về SSR, bạn cũng có thể tìm hiểu cách triển khai SSR của React sau này.
Tôi hy vọng nó sẽ hữu ích cho bạn Nếu có bất kỳ sai sót nào, vui lòng sửa chúng.
thẩm quyền giải quyết
Tại sao nên sử dụng kết xuất phía máy chủ (SSR)?
Đọc chuyên sâu mã nguồn Nuxt.
Vue Meta.
Giới thiệu về tính năng tải trước thông minh.
Kết xuất phía máy chủ.
Liên kết gốc: https://mp.weixin.qq.com/s/fvv12ZPxiEpCzER3Q-X5pQ.
Cuối cùng, bài viết nói về các tính năng sẵn có của Nuxt kết thúc ở đây. Nếu bạn muốn biết thêm về cách nói về các tính năng sẵn dùng của Nuxt, vui lòng tìm kiếm các bài viết về CFSDN hoặc tiếp tục duyệt các bài viết liên quan. ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!