<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Webpack5構(gòu)造React多頁(yè)面應(yīng)用

          共 11635字,需瀏覽 24分鐘

           ·

          2021-01-08 06:31


          來(lái)源 |?https://github.com/zhedh/react-multi-page-app/

          介紹

          react-multi-page-app是一個(gè)基于webpack5構(gòu)造的react多頁(yè)面應(yīng)用。
          為什么建造多頁(yè)面應(yīng)用:
          • 多個(gè)頁(yè)面之間業(yè)務(wù)互不關(guān)聯(lián),頁(yè)面之間并沒有共享的數(shù)據(jù)

          • 多個(gè)頁(yè)面使用同一個(gè)一個(gè)服務(wù),使用通用的組件和基礎(chǔ)庫(kù)

          建造多頁(yè)面應(yīng)用的好處:
          • 保留了傳統(tǒng)單頁(yè)應(yīng)用的開發(fā)模式:支持補(bǔ)充打包,你可以把每個(gè)頁(yè)面看成是一個(gè)單獨(dú)的單頁(yè)應(yīng)用

          • 獨(dú)立部署:每個(gè)頁(yè)面相互獨(dú)立,可以單獨(dú)部署,解壓縮項(xiàng)目的復(fù)雜性,甚至可以在不同的頁(yè)面選擇不同的技術(shù)棧

          • 減少包的體積,優(yōu)化加載渲染流程

          快速上手

          克隆
          git clone https://github.com/zhedh/react-multi-page-app.git
          安裝依賴
          yarn install
          開發(fā)
          yarn start
          http:// localhost:8000 / page1 ?
          打包
          yarn build

          簡(jiǎn)易建設(shè)流程

          npm初始化

          yarn init

          約定目錄

          |____README.md|____package.json|____src| |____utils| |____components| |____pages| | |____page2| | | |____index.css| | | |____index.jsx| | |____page1| | | |____index.css| | | |____index.jsx

          webpack配置

          安裝webpack
          yarn add -D可以使用npm?i --save-dev替代
          yarn add -D webpack webpack-cli
          創(chuàng)建配置文件
          touch webpack.config.js
          入口配置
          module.exports = { entry: { page1: "./src/pages/page1/index.jsx", page2: "./src/pages/page2/index.jsx", // ... },};
          輸出配置
          module.exports = { entry: { page1: "./src/pages/page1/index.jsx", page2: "./src/pages/page2/index.jsx", // ... }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name]/index.js", },};
          js | jsx編譯
          安裝babel插件
          yarn add -D babel-loader @babel/core @babel/preset-env
          module.exports = { ... module: { rules: [ { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] },}
          css編譯
          安裝裝載機(jī)
          yarn add -D style-loader css-loader
          module.exports = { ... module: { ... rules: [ { test: /\.css$/i, use: [ 'style-loader', 'css-loader' ], }, ] },}
          html插件配置
          安裝html?-webpack-plugin
          yarn add -D html-webpack-plugin
          module.exports = { ... plugins: [ new HtmlWebpackPlugin({ filename: 'page1/index.html', chunks: ['page1'] }), new HtmlWebpackPlugin({ filename: 'page2/index.html', chunks: ['page2'] }), ],}

          頁(yè)面編輯

          第1頁(yè)
          index.jsx
          import "./index.css";
          document.querySelector("body").append("PAGE1");
          index.css
          body { color: blue;}
          第2頁(yè)
          index.jsx
          import "./index.css";
          document.querySelector("body").append("PAGE2");
          index.css
          body { color: green;}

          打包

          執(zhí)行
          webpack
          輸出dist包產(chǎn)物如下:
          ├── page1│ ├── index.html│ └── index.js└── page2 ├── index.html └── index.js

          完整的配置文件

          webpack.config.js
          const path = require("path");const HtmlWebpackPlugin = require("html-webpack-plugin");
          module.exports = { entry: { page1: "./src/pages/page1/index.jsx", page2: "./src/pages/page2/index.jsx", }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name]/index.js", }, module: { rules: [ { test: /\.css$/i, use: ["style-loader", "css-loader"], }, { test: /\.m?jsx$/, exclude: /(node_modules|bower_components)/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, ], }, plugins: [ new HtmlWebpackPlugin({ filename: "page1/index.html", chunks: ["page1"], // chunks: ['page1', 'page1/index.css'] }), new HtmlWebpackPlugin({ filename: "page2/index.html", chunks: ["page2"], }), ],};
          package.json
          { "name": "react-multi-page-app", "version": "1.0.0", "description": "react 多頁(yè)面應(yīng)用", "main": "index.js", "license": "MIT", "devDependencies": { "@babel/core": "^7.12.9", "@babel/preset-env": "^7.12.7", "babel-loader": "^8.2.2", "css-loader": "^5.0.1", "html-webpack-plugin": "^4.5.0", "style-loader": "^2.0.0", "webpack": "^5.9.0", "webpack-cli": "^4.2.0" }}
          去github查看簡(jiǎn)易版完整代碼react-multi-page-app

          流程優(yōu)化

          分離開發(fā)生產(chǎn)環(huán)境

          新建配置目錄,并創(chuàng)建配置文件
          mkdir configcd configtouch webpack.base.jstouch webpack.dev.jstouch webpack.prod.js
          ├── webpack.base.js├── webpack.dev.js└── webpack.prod.js
          基礎(chǔ)配置
          webpack.base.js
          const path = require("path");const HtmlWebpackPlugin = require("html-webpack-plugin");
          module.exports = { entry: { page1: "./src/pages/page1/index.jsx", page2: "./src/pages/page2/index.jsx", }, output: { path: path.resolve(__dirname, "./dist"), filename: "[name]/index.js", }, module: { rules: [ { test: /\.css$/i, use: ["style-loader", "css-loader"], }, { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], }, }, }, ], }, plugins: [ new HtmlWebpackPlugin({ filename: "page1/index.html", chunks: ["page1"], }), new HtmlWebpackPlugin({ filename: "page2/index.html", chunks: ["page2"], }), ],};
          開發(fā)配置
          • 安裝webpack-merge,用于合并webpack配置信息

          yarn add -D webpack-merge
          • 安裝webpack-dev-server,用于啟動(dòng)開發(fā)服務(wù)

          yarn add -D webpack-dev-server
          • 開發(fā)配置如下

          webpack.dev.js
          const { merge } = require("webpack-merge");const path = require("path");const base = require("./webpack.base");
          module.exports = merge(base, { mode: "development", devtool: "inline-source-map", target: "web", devServer: { open: true, contentBase: path.join(__dirname, "./dist"), historyApiFallback: true, //不跳轉(zhuǎn) inline: true, //實(shí)時(shí)刷新 hot: true, // 開啟熱更新, port: 8000, },});
          • 配置啟動(dòng)命令

          package.json
          { "scripts": { "start": "webpack serve --mode development --env development --config config/webpack.dev.js" },}
          • 啟動(dòng)

          yarn start
          • 預(yù)覽

          http:// localhost:8000 / page1
          http:// localhost:8000 / page2
          生產(chǎn)配置
          配置如下
          webpack.prod.js
          const { merge } = require('webpack-merge')const base = require('./webpack.base')
          module.exports = merge(base, { mode: 'production',})
          配置打包命令
          package.json
          { "scripts": { "start": "webpack serve --mode development --env development --config config/webpack.dev.js", "build": "webpack --config config/webpack.prod.js" },}
          打包
          yarn build

          ?反應(yīng)

          以page1頁(yè)面為例
          約定目錄
          ├── page1│ ├── app.jsx│ ├── index.jsx│ └── index.css└── page2 ├── app.js ├── index.jsx └── index.css
          安裝反應(yīng)
          yarn add react react-dom
          代碼如下
          app.js
          import React from 'react'
          function App() { return (
          我是PAGE1,Hello World
          )}
          export default App
          index.js
          import React from 'react'import ReactDOM from 'react-dom'import App from './app'import './index.css'
          ReactDOM.render(, document.getElementById('root'))
          index.css
          body{ background-color: #ccc;}
          #page1 { color: rebeccapurple;}
          添加反應(yīng)編譯
          webpack.base.js
          module.exports = { module: { // ... rules: [ // ... { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], plugins: ['@babel/plugin-proposal-class-properties'] } } } ] }, // ...}
          省略獲取文件后綴
          webpack.base.js
          module.exports = { // ... resolve: { extensions: ['.js', '.jsx', '.json'] }}
          添加html樣式模版,掛載React DOM
          cd srctouch template.html
          template.html

          Document

          webpack.base.js
          module.exports = { plugins: [ new HtmlWebpackPlugin({ filename: 'page1/index.html', chunks: ['page1'], template: './src/template.html' }), new HtmlWebpackPlugin({ filename: 'page2/index.html', chunks: ['page2'], template: './src/template.html' }), ],}
          安裝依賴
          yarn add @babel/preset-react @babel/plugin-proposal-class-properties

          ass

          以page1首先
          將index.css變更為index.scss
          index.scss
          body { background-color: #ccc;
          #page1 { color: rebeccapurple; }}
          添加scss編譯
          webpack.base.js
          module.exports = { // ... module: { // ... rules: [ { test: /\.(sa|sc|c)ss$/, use: [ 'style-loader', 'css-loader', 'resolve-url-loader', 'sass-loader' ] }, ] }, // ...}
          安裝依賴
          yarn add -D resolve-url-loader sass-loader
          到此,一個(gè)完整的React多頁(yè)面應(yīng)用構(gòu)建完成,查看完整代碼react-multi-page-app

          入口配置和模版自動(dòng)匹配

          為了不用每次補(bǔ)充頁(yè)面都要添加入口頁(yè)面配置,我們將入口配置改成自動(dòng)匹配
          入口文件自動(dòng)匹配
          cd configtouch webpack.util.js
          webpack.util.js
          const glob = require('glob')
          function setEntry() { const files = glob.sync('./src/pages/**/index.jsx') const entry = {} files.forEach(file => { const ret = file.match(/^\.\/src\/pages\/(\S*)\/index\.jsx$/) if (ret) { entry[ret[1]] = { import: file, } } })
          return entry}
          module.exports = { setEntry,}
          webpack.base.js
          const { setEntry } = require('./webpack.util')
          module.exports = { entry: setEntry,}
          拆分React依賴,將React單獨(dú)打包出一個(gè)bundle,作為公共依賴帖子各個(gè)頁(yè)面
          webpack.util.js
          function setEntry() { const files = glob.sync('./src/pages/**/index.jsx') const entry = {} files.forEach(file => { const ret = file.match(/^\.\/src\/pages\/(\S*)\/index\.jsx$/) if (ret) { entry[ret[1]] = { import: file, dependOn: 'react_vendors', } } })
          // 拆分react依賴 entry['react_vendors'] = { import: ['react', 'react-dom'], filename: '_commom/[name].js' }
          return entry}
          html模版自動(dòng)匹配,并約會(huì)反應(yīng)包
          以page1為例子,約會(huì)頁(yè)面自定義模版目錄約定如下
          ├── app.jsx├── index.html├── index.jsx└── index.scss
          index.html

          頁(yè)面1

          如果匹配不到自定義模版,會(huì)匹配替換模版,配置如下:
          webpack.util.js
          function getTemplate(name) { const files = glob.sync(`./src/pages/${name}/index.html`) if (files.length > 0) { return files[0] } return './src/template.html'}
          function setHtmlPlugin() { const files = glob.sync('./src/pages/**/index.jsx') const options = [] files.forEach(file => { const ret = file.match(/^\.\/src\/pages\/(\S*)\/index\.jsx$/) if (ret) { const name = ret[1] options.push(new HtmlWebpackPlugin({ filename: `${name}/index.html`, template: getTemplate(name), chunks: ['react_vendors', name,] })) } }) return options}
          module.exports = { setEntry, setHtmlPlugin}
          webpack.base.js
          const { setEntry, setHtmlPlugin } = require('./webpack.util')
          module.exports = { plugins: [ ...setHtmlPlugin(), ]}
          安裝相關(guān)依賴
          yarn add -D html-webpack-plugin glob

          配置優(yōu)化

          清除之前打包文件
          webpack.base.js
          const HtmlWebpackPlugin = require('html-webpack-plugin')
          module.exports = { plugins: [ new CleanWebpackPlugin(), ]}
          yarn add -D clean-webpack-plugin
          分離并壓縮css
          webpack.base.js
          const MiniCssExtractPlugin = require('mini-css-extract-plugin')const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
          module.exports = { module: { rules: [ { test: /\.(sa|sc|c)ss$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'resolve-url-loader', 'sass-loader' ] }, ] }, plugins: [ new MiniCssExtractPlugin({ filename: '[name]/index.css', }), new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }) ]}
          html中注入css
          webpack.util.js
          function setHtmlPlugin() { const files = glob.sync('./src/pages/**/index.jsx') const options = [] files.forEach(file => { const ret = file.match(/^\.\/src\/pages\/(\S*)\/index\.jsx$/) if (ret) { const name = ret[1] options.push(new HtmlWebpackPlugin({ filename: `${name}/index.html`, template: getTemplate(name), chunks: ['react_vendors', name, '[name]/index.css'] })) } }) return options}
          yarn add -D mini-css-extract-plugin optimize-css-assets-webpack-plugin
          在 package.json 配置 sideEffects,避免 webpack Tree Shaking 移除.css、.scss 文件package.json
          ```json{ "sideEffects": [ "*.css", "*.scss" ]}
          至此,項(xiàng)目配置完成

          項(xiàng)目源碼

          完整代碼:https://github.com/zhedh/react-multi-page-app/,喜歡給個(gè)star

          問題與解答

          無(wú)法讀取未定義的屬性“ createSnapshot”
          報(bào)錯(cuò):UnhandledPromiseRejectionWarning:TypeError:無(wú)法讀取未定義的屬性'createSnapshot'
          原因:因?yàn)橥瑫r(shí)運(yùn)行2個(gè)不同版本的webpack。我們項(xiàng)目中沒有安裝webpack-cli,webpack會(huì)進(jìn)行交替使用的webpack-cli,webpack5和webpack-cli3不兼容
          解決:升級(jí)版本webpack-cli3到webpack-cli4或在項(xiàng)目中安裝最新版本的webpack-cli4
          參考:https?:?//github.com/

          本文完?

          最后


          • 歡迎加我微信(winty230),拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          • 歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專業(yè)的技術(shù)人...

          點(diǎn)個(gè)在看支持我吧

          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  老女人性爱网 | 欧美激情性爱网站 | www.色国产 | 吃瓜偷拍AV一区二区三区 | 视频精品一区二区三区 |