摘要:又從開始學(xué)習(xí)新的東西了,想著還是記錄一下學(xué)習(xí)歷程,有輸入就要有輸出吧,免得以后給忘記學(xué)了些什么框架與主流工具的整合地址首先,項目,學(xué)習(xí)里面的。如有錯誤和問題歡迎各位大佬不吝賜教輕量級框架與主流工具的整合二完善與優(yōu)化
前言
老大說以后會用 next 來做一下 SSR 的項目,讓我們有空先學(xué)學(xué)。又從 0 開始學(xué)習(xí)新的東西了,想著還是記錄一下學(xué)習(xí)歷程,有輸入就要有輸出吧,免得以后給忘記學(xué)了些什么~
Next框架與主流工具的整合github地址:https://github.com/code-coder/next-mobile-complete-app
?? 數(shù)據(jù)層:redux + saga
?? 視圖層:sass + postcss
?? 服務(wù)端:koa
做一個項目就像造一所房子,最開始就是“打地基”: 1. 新建了一個項目,用的是這里面的一個with-redux-saga的template 戳這里。 2. 添加sass和postcss,參考的是 這里新建next.config.js,復(fù)制以下代碼:
const withSass = require("@zeit/next-sass"); module.exports = withSass({ postcssLoaderOptions: { parser: true, config: { ctx: { theme: JSON.stringify(process.env.REACT_APP_THEME) } } } });
新建postcss.config.js,復(fù)制以下代碼:
module.exports = { plugins: { autoprefixer: {} } };
在package.js添加自定義browserList,這個就根據(jù)需求來設(shè)置了,這里主要是移動端的。
// package.json "browserslist": [ "IOS >= 8", "Android > 4.4" ],
順便說一下browserlist某些配置會報錯,比如直接填上默認配置
"browserslist": [ "last 1 version", "> 1%", "maintained node versions", "not dead" ] // 會報以下錯誤 Unknown error from PostCSS plugin. Your current PostCSS version is 6.0.23, but autoprefixer uses 5.2.18. Perhaps this is the source of the error below.3. 配置koa,參照custom-server-koa
新建server.js文件,復(fù)制以下代碼:
const Koa = require("koa"); const next = require("next"); const Router = require("koa-router"); const port = parseInt(process.env.PORT, 10) || 3000; const dev = process.env.NODE_ENV !== "production"; const app = next({ dev }); const handle = app.getRequestHandler(); app.prepare().then(() => { const server = new Koa(); const router = new Router(); router.get("*", async ctx => { await handle(ctx.req, ctx.res); ctx.respond = false; }); server.use(async (ctx, next) => { ctx.res.statusCode = 200; await next(); }); server.use(router.routes()); server.listen(port, () => { console.log(`> Ready on http://localhost:${port}`); }); });
然后在配置一下package.json的scripts
"scripts": { "dev": "node server.js", "build": "next build", "start": "NODE_ENV=production node server.js" }現(xiàn)在只是把地基打好了,接著需要完成排水管道、鋼筋架構(gòu)等鋪設(shè):
?? 調(diào)整項目結(jié)構(gòu)
?? layout布局設(shè)計
?? 請求攔截、loading狀態(tài)及錯誤處理
1. 調(diào)整后的項目結(jié)構(gòu)-- components -- pages ++ server || -- server.js -- static ++ store || ++ actions || -- index.js || ++ reducers || -- index.js || ++ sagas || -- index.js -- styles -- next.config.js -- package.json -- postcss.config.js -- README.md2. layout布局設(shè)計。
ant design 是我使用過而且比較有好感的UI框架。既然這是移動端的項目,ant design mobile 成了首選的框架。我也看了其他的主流UI框架,現(xiàn)在流行的UI框架有Amaze UI、Mint UI、Frozen UI等等,個人還是比較喜歡ant出品的。
恰好templates中有ant design mobile的demo:with-ant-design-mobile。
基于上面的項目結(jié)構(gòu)整合with-ant-design-mobile這個demo。
新增babel的配置文件:.babelrc 添加以下代碼:
{ "presets": ["next/babel"], "plugins": [ [ "import", { "libraryName": "antd-mobile" } ] ] }
修改next.config.js為:
const withSass = require("@zeit/next-sass"); const path = require("path"); const fs = require("fs"); const requireHacker = require("require-hacker"); function setupRequireHacker() { const webjs = ".web.js"; const webModules = ["antd-mobile", "rmc-picker"].map(m => path.join("node_modules", m)); requireHacker.hook("js", filename => { if (filename.endsWith(webjs) || webModules.every(p => !filename.includes(p))) return; const webFilename = filename.replace(/.js$/, webjs); if (!fs.existsSync(webFilename)) return; return fs.readFileSync(webFilename, { encoding: "utf8" }); }); requireHacker.hook("svg", filename => { return requireHacker.to_javascript_module_source(`#${path.parse(filename).name}`); }); } setupRequireHacker(); function moduleDir(m) { return path.dirname(require.resolve(`${m}/package.json`)); } module.exports = withSass({ webpack: (config, { dev }) => { config.resolve.extensions = [".web.js", ".js", ".json"]; config.module.rules.push( { test: /.(svg)$/i, loader: "emit-file-loader", options: { name: "dist/[path][name].[ext]" }, include: [moduleDir("antd-mobile"), __dirname] }, { test: /.(svg)$/i, loader: "svg-sprite-loader", include: [moduleDir("antd-mobile"), __dirname] } ); return config; } });
static新增rem.js
(function(doc, win) { var docEl = doc.documentElement, // isIOS = navigator.userAgent.match(/(i[^;]+;( U;)? CPU.+Mac OS X/), // dpr = isIOS ? Math.min(win.devicePixelRatio, 3) : 1; // dpr = window.top === window.self ? dpr : 1; //被iframe引用時,禁止縮放 dpr = 1; var scale = 1 / dpr, resizeEvt = "orientationchange" in window ? "orientationchange" : "resize"; docEl.dataset.dpr = dpr; var metaEl = doc.createElement("meta"); metaEl.name = "viewport"; metaEl.content = "initial-scale=" + scale + ",maximum-scale=" + scale + ", minimum-scale=" + scale + ",user-scalable=no"; docEl.firstElementChild.appendChild(metaEl); var recalc = function() { var width = docEl.clientWidth; // 大于1280按1280來算 if (width / dpr > 1280) { width = 1280 * dpr; } // 乘以100,px : rem = 100 : 1 docEl.style.fontSize = 100 * (width / 375) + "px"; doc.body && doc.body.style.height !== docEl.clientHeight && docEl.clientHeight > 360 && (doc.body.style.height = docEl.clientHeight + "px"); }; recalc(); if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); win.onload = () => { doc.body.style.height = docEl.clientHeight + "px"; }; })(document, window);
增加移動端設(shè)備及微信瀏覽器的判斷
(function() { // 判斷移動PC端瀏覽器和微信端瀏覽器 var ua = navigator.userAgent; // var ipad = ua.match(/(iPad).* OSs([d _] +)/); var isAndroid = ua.indexOf("Android") > -1 || ua.indexOf("Adr") > -1; // android var isIOS = !!ua.match(/(i[^;]+;( U;)? CPU.+Mac OS X/); // ios if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) { window.isAndroid = isAndroid; window.isIOS = isIOS; window.isMobile = true; } else { // 電腦PC端判斷 window.isDeskTop = true; } ua = window.navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == "micromessenger") { window.isWeChatBrowser = true; } })();
_document.js新增引用: