倉庫地址:gitee.com/dreamer2011…javascript
本項目適用於移動端H5
混合開發的React項目
,功能包括:css
字體自動適配
,默認按照UI設計稿750*1334
(webpack裏能夠配置UI稿原始尺寸)上下適配各類手機設備;sprite
雪碧圖和相關 sprite.less
,無需手動建立雪碧圖和手寫less;webpack4最新構建
,分離壓縮代碼、去除重複引用的css代碼、開發環境生成sourceMap方便調試、生產環境移除console.log打印信息等構建,並生成相關gz包
,優化頁面資源加載;Fetch封裝 dataService 服務
,統一格式進行相關接口的GET, POST請求;FetchData.jsx
, 進行組件數據預加載和狀態注入;React router components
進行 lazing load 懶加載
, 帶有組件預加載loading
和加載失敗error提示
,增長頁面友好提示,性能也更加優化;liveServer
對生成的PROD生產環境代碼,進行預先運行檢查;browserHistory
路由模式,相關本地環境配置已經自動配置(上線時,須要在服務器配置nginx
)自動生成
文件夾保存當前打包生成的tar包
, 防止線上部署失敗; 有備份的話能夠回滾以前的代碼版本;若是拋卻相關app h5設置,可看成 PC 項目,兼容 ie9+
;手機端調試面板
,功能至關於打開 PC 控制檯,能夠很方便地查看 console, network, cookie, localStorage 等關鍵調試信息;Sentry監控代碼異常錯誤上報
,訪問 f5fe3d6e599849bfa1d1f0c26d1c3213@sentry.io/1729437,查看報…Bundle分析報告report
Local Server:html
yarn dev
#or
npm run dev
複製代碼
build bundle:java
yarn build
#or
npm run build
複製代碼
生成 tar 包node
# 默認生產 cdn.tar.gz
yarn tar
#or
npm run tar
# 能夠自定義tar包名
yarn tar react
#or
npm run tar react
複製代碼
測試打包後要上線的代碼:react
yarn start
#or
npm run start
複製代碼
webpack.config.jswebpack
{
test: /\.less$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'less-loader',
// 配置相關移動端 VW 佈局
{
loader: 'postcss-less-loader',
options: {
ident: 'postcss',
plugins: () => [
postcssPxToViewport({
viewportWidth: 750, // (Number) The width of the viewport.
viewportHeight: 1334, // (Number) The height of the viewport.
unitPrecision: 3, // (Number) The decimal numbers to allow the REM units to grow to.
viewportUnit: 'vw', // (String) Expected units.
selectorBlackList: ['.ignore', '.hairlines'], // (Array) The selectors to ignore and leave as px.
minPixelValue: 1, // (Number) Set the minimum pixel value to replace.
mediaQuery: false // (Boolean) Allow px to be converted in media queries.
})
]
}
}
]
}
複製代碼
webpack.config.jsnginx
// 圖片整合成雪碧圖
const SpritesmithPlugin = require('webpack-spritesmith');
// customerTemplate
const templateFunction = function(data) {
// console.log('---', data)
const shared = `.sprite_ico { background-image: url(I);display:inline-block;background-size: Wpx Hpx;}`
.replace('I', data.sprites[0].image)
.replace('W', data.spritesheet.width)
.replace('H', data.spritesheet.height);
const perSprite = data.sprites
.map(function(sprite) {
return `.sprite_ico_N { width: Wpx; height: Hpx; background-position: Xpx Ypx;}`
.replace('N', sprite.name)
.replace('W', sprite.width)
.replace('H', sprite.height)
.replace('X', sprite.offset_x)
.replace('Y', sprite.offset_y);
})
.join('\n');
return "//out:false" + '\n'+shared + '\n' + perSprite;
};
// 雪碧圖
plugins.push(
new SpritesmithPlugin({
src: {
//下面的路徑,根據本身的實際路徑配置
cwd: path.resolve(__dirname, './src/assets/icons'),
glob: '*.png'
},
// 輸出雪碧圖文件及樣式文件
target: {
//下面的路徑,根據本身的實際路徑配置
image: path.resolve(__dirname, './src/assets/sprite.png'),
css: [
[
path.resolve(__dirname, './src/less/sprite.less'),
{
format: 'function_based_template'
}
]
]
// css: path.resolve(__dirname, './src/less/sprite.less')
},
// 自定義模板
customTemplates: {
function_based_template: templateFunction
},
// 樣式文件中調用雪碧圖地址寫法
apiOptions: {
// 這個路徑根據本身頁面配置
cssImageRef: '../assets/sprite.png'
},
spritesmithOptions: {
// algorithm: 'top-down'
padding: 5
}
})
);
複製代碼
icon格式須要是
png
, 把須要生成雪碧圖的小icon放置在目錄src/assets/icons
下面,而後執行yarn build
,就能夠在src\less\sprite.less
下去找本身的圖標ICON的className
;好比:git
使用的時候,直接引入 sprite_ico sprite_ico_guzhi
便可;無需配置引入sprite.less
文件;github
<span className="sprite_ico sprite_ico_guzhi"></span>
複製代碼
React 組件必須首字母大寫,其餘請參考官網
cdn --------------構建後的資源
public --------------靜態資源
src --------------全部React資源
actions --------------- 相關action
assets --------------- 全部靜態圖片資源
components ------------ 公共組件
dataService----------- 請求服務
less ------------------ less文件
pages ----------------- 全部入口文件下的子文件
reducers -------------- reducer
router ---------------- 路由設置
store ----------------- 狀態存儲
utils ----------------- 公共方法
.....其他都是App.jsx login.jsx等入口文件
tar --------------構建備份的tar
....
複製代碼
index.html
<script src="https://cdn.ravenjs.com/3.26.4/raven.min.js" crossorigin="anonymous"></script>
// 代碼錯誤監控 Raven.config('https://f5fe3d6e599849bfa1d1f0c26d1c3213@sentry.io/1729437').install();
複製代碼
添加 ==React ErrorBoundary== 組件,具體能夠參考官方文檔 :
import React from 'react';
import oops from "@assets/oops.png";
// catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
}
componentDidCatch(error, errorInfo) {
this.setState({ error });
Raven.captureException(error, { extra: errorInfo });
}
render() {
if (this.state.error) {
//render fallback UI
return (
<div className="snap" onClick={() => Raven.lastEventId() && Raven.showReportDialog()}>
<img src={oops} />
<p>We're sorry — something's gone wrong.</p>
<p>Our team has been notified, but click here fill out a report.</p>
</div>
);
} else {
//when there's not an error, render children untouched
return this.props.children;
}
}
}
export default ErrorBoundary;
複製代碼
此時若是咱們如今故意改錯一些東西,則會提示 fallback UI:
點擊文字,用戶能夠主動發一個 issue 給咱們:
目前報錯信息會上傳到 sentry.io,也能夠建立本身的私服;
index.html
//在手機端進行查看控制檯相關資源
(function () {
//推薦 CDN 加載
const src = 'https://cdn.jsdelivr.net/npm/eruda@1.5.8/eruda.min.js';
// var src = 'node_modules/eruda/eruda.min.js';
if (!/debug=true/.test(window.location) && localStorage.getItem('debug') != 'true') return;
document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
document.write('<scr' + 'ipt>eruda.init();</scr' + 'ipt>');
})();
複製代碼
啓動項目後,訪問 http://192.168.1.100:3002/?debug=true , 在手機上如圖:
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
複製代碼
舉例:
import React from 'react';
class HammerPan extends React.Component {
render() {
return <div className="myElement">888</div>;
}
componentDidMount() {
const myElement = document.querySelector('.myElement');
// create a simple instance
// by default, it only adds horizontal recognizers
const mc = new Hammer(myElement);
// let the pan gesture support all directions.
// this will block the vertical scrolling on a touch-device while on the element
mc.get('pan').set({ direction: Hammer.DIRECTION_ALL });
// listen to events...
mc.on('panleft panright panup pandown tap press', ev => {
myElement.textContent = ev.type + ' gesture detected.';
});
}
}
export default HammerPan;
複製代碼
啓動項目後,訪問 http://192.168.1.100:3002/pan,便可查看
# NPM
npm install --save-dev webpack-bundle-analyzer
# Yarn
yarn add -D webpack-bundle-analyzer
複製代碼
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
複製代碼
package.json
"scripts": {
"dev": "webpack-dev-server --mode development",
"build": "bash ./rm.sh && webpack --mode production --profile --json > stats.json && yarn tar",
"start": "node ./server.js",
"tar": "bash ./tar.sh"
}
複製代碼