资讯专栏INFORMATION COLUMN

Next轻量级框架与主流工具的整合

FWHeart / 884人阅读

摘要:又从开始学习新的东西了,想着还是记录一下学习历程,有输入就要有输出吧,免得以后给忘记学了些什么框架与主流工具的整合地址首先,项目,学习里面的。如有错误和问题欢迎各位大佬不吝赐教轻量级框架与主流工具的整合二完善与优化

前言

老大说以后会用 next 来做一下 SSR 的项目,让我们有空先学学。又从 0 开始学习新的东西了,想着还是记录一下学习历程,有输入就要有输出吧,免得以后给忘记学了些什么~

Next框架与主流工具的整合

github地址:https://github.com/code-coder/next-mobile-complete-app

首先,clone Next.js 项目,学习里面的templates。
打开一看,我都惊呆了,差不多有150个搭配工具个template,有点眼花缭乱。
这时候就需要明确一下我们要用哪些主流的工具了:

✔️ 数据层:redux + saga

✔️ 视图层:sass + postcss

✔️ 服务端:koa

做一个项目就像造一所房子,最开始就是“打地基”: 1. 新建了一个项目,用的是这里面的一个with-redux-saga的template 戳这里。 2. 添加sass和postcss,参考的是 这里

新建next.config.js,复制以下代码:

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,复制以下代码:

module.exports = {
  plugins: {
    autoprefixer: {}
  }
};

package.js添加自定义browserList,这个就根据需求来设置了,这里主要是移动端的。

// 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文件,复制以下代码:

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"
  }
现在只是把地基打好了,接着需要完成排水管道、钢筋架构等铺设:

✔️ 调整项目结构

✔️ layout布局设计

✔️ 请求拦截、loading状态及错误处理

1. 调整后的项目结构
-- 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.md
2. layout布局设计。

ant design 是我使用过而且比较有好感的UI框架。既然这是移动端的项目,ant design mobile 成了首选的框架。我也看了其他的主流UI框架,现在流行的UI框架有Amaze UI、Mint UI、Frozen UI等等,个人还是比较喜欢ant出品的。

恰好templates中有ant design mobile的demo:with-ant-design-mobile。

基于上面的项目结构整合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);

增加移动端设备及微信浏览器的判断

(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新增引用


                    
阅读需要支付1元查看
<