乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      初次搭建Next.js項(xiàng)目歷程(精)

       新進(jìn)小設(shè)計(jì) 2020-03-01

      使用create-next-app初始化項(xiàng)目

      create-next-app和react官方提供的create-react-app(CRA)非常像,next.js官方也自帶了create-next-app(CNA),所以直接安裝就好。

      sudo yarn global add create-next-app

      安裝好之后就可以創(chuàng)建項(xiàng)目了

      create-next-app project-name

      生成之后的目錄結(jié)構(gòu)如下

          |-- .gitignore
          |-- package.json
          |-- yarn.lock
          |-- components
          |   |-- nav.js
          |-- pages
          |   |-- index.js
          |-- public
              |-- favicon.ico
      

      我們可以查看下package.json

      package.json

      {
        "name": "next-demo4",
        "version": "0.1.0",
        "private": true,
        "scripts": {
          "dev": "next dev",
          "build": "next build",
          "start": "next start"
        },
        "dependencies": {
          "next": "9.1.4",
          "react": "16.12.0",
          "react-dom": "16.12.0"
        }
      }
      

      然后執(zhí)行yarn dev運(yùn)行起來(lái)試試

      image.png

      配置koa路由

      安裝好了之后,我們可以設(shè)置成koa路由,首先添加koa 和 koa-router依賴包,然后在根目錄下添加server.js文件,如下:

      yarn add koa koa-router

      server.js

      const Koa = require("koa");
      const next = require("next");
      const Router = require("koa-router");
      
      const port = parseInt(process.env.PORT, 10) || 3003;
      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 app.render(ctx.req, ctx.res, "/", ctx.query);
          ctx.respond = false;
        });
      
        router.all("*", 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": {
          "dev": "next dev",
          "build": "next build",
          "start": "next start",
      +   "koa": "node server.js -p 3003"
        },

      我們現(xiàn)在執(zhí)行yarn koa試試,運(yùn)行成功!

      通過(guò)next.js官方提供的example案例來(lái)配置redux和immutable.js

      next.js官方案例提供了周邊框架的搭建實(shí)例,方便開(kāi)發(fā)人員配置相關(guān)框架和插件,如下所示:
      image.png

      首先我們先來(lái)安裝redux相關(guān)依賴包,如下

      yarn add redux redux-actions redux-saga redux-logger

      接著我們找一下我們要搭建的redux和immutable.js相關(guān)實(shí)例:with-redux-saga和with-immutable-redux-wrapper,然后自己一點(diǎn)點(diǎn)的去配置,當(dāng)然中間肯定遇到了各種各樣的問(wèn)題,這里就不詳細(xì)說(shuō)明了,只展示配置好運(yùn)行起來(lái)沒(méi)問(wèn)題的代碼分享給大家,如下所示:

      _app.js

      import React from "react";
      import { Provider } from "react-redux";
      import App, { Container } from "next/app";
      import withRedux from "next-redux-wrapper";
      import withReduxSaga from "next-redux-saga";
      import { fromJS } from "immutable";
      import configureStore from "../service/redux/store";
      import "../assets/styles/index.css";
      import "antd/dist/antd.css";
      
      @withRedux(configureStore)
      @withReduxSaga
      class NextApp extends App {
        static async getInitialProps({ Component, ctx }) {
          let pageProps = {};
          if (Component.getInitialProps) {
            pageProps = await Component.getInitialProps({ ctx });
          }
          return { pageProps };
        }
      
        render() {
          const { Component, pageProps, store } = this.props;
          return (
            <Container>
              <Provider store={store}>
                <Component {...pageProps} />
              </Provider>
            </Container>
          );
        }
      }
      
      export default NextApp;
      

      store.js

      import { createStore, compose, applyMiddleware } from "redux";
      import createSagaMiddleware from "redux-saga";
      import logger from "redux-logger";
      import rootReducer from "./reducers";
      import rootSaga from "./sagas";
      import { fromJS } from "immutable";
      
      // create the saga middleware
      const sagaMiddleware = createSagaMiddleware();
      
      // 組合middleware
      const middleWares = [sagaMiddleware, logger];
      
      export default function configureStore(preloadedState = fromJS({})) {
        const store = createStore(rootReducer, applyMiddleware(...middleWares));
      
        store.sagaTask = sagaMiddleware.run(rootSaga);
        return store;
      }
      

      reducers.js

      import { combineReducers } from "redux";
      import { autoCombineReducer } from "../../utils/autoCombineRedux";
      
      export default combineReducers(autoCombineReducer());
      

      sagas.js

      import { all, fork } from "redux-saga/effects";
      import { autoCombineSaga } from "../../utils/autoCombineRedux";
      
      /*添加對(duì)action的監(jiān)聽(tīng) */
      export default function* rootSaga() {
        yield all(autoCombineSaga());
      }
      

      這里我說(shuō)明下reducers.js和sagas.js用到的方法:autoCombineReducer和autoCombineSaga,以前我們寫reducer.js或者saga.js是把相關(guān)reducer或者saga文件import進(jìn)來(lái),然后注入到combineReducers()方法或者yield all()里面,好處是直觀,壞處就是每次寫一個(gè)reducer或者saga文件就要在這里加一下,是不是覺(jué)得非常麻煩,索性自己寫一個(gè)自動(dòng)注冊(cè)進(jìn)combineReducers()或者yield all()的方法,這個(gè)方法利用webpack的CONTEXT(require.context)把文件夾下名稱為reducer.js或者saga.js文件自動(dòng)加載進(jìn)來(lái),詳細(xì)請(qǐng)看下面代碼:

      autoCombineRedux.js

      import { all, fork } from "redux-saga/effects";
      
      // 查詢所有文件夾下的所有文件名,以文件名數(shù)組形式返回
      const getContext = (path, type) => {
        let CONTEXT = type == "reducer" ? require.context(".", true, /reducer\.js$/) : require.context(".", true, /saga\.js$/);
        if (path == "../") {
          CONTEXT = type == "reducer" ? require.context("../", true, /reducer\.js$/) : require.context("../", true, /saga\.js$/);
        }
        if (path == "../../") {
          CONTEXT = type == "reducer" ? require.context("../../", true, /reducer\.js$/) : require.context("../../", true, /saga\.js$/);
        }
        return CONTEXT;
      };
      
      export const autoCombineReducer = (path = "../") => {
        let CONTEXT = getContext(path, "reducer");
      
        // 獲取完組合成reducer對(duì)象
        const importReducer = req => (obj, path) => {
          //從路徑中獲取reducer name
          // output:[0: "demo",groups: undefined,index: 7,input: "./demo/reducer.js"]
          const [componentName] = path.match(/\w+(?=\/reducer\.js$)/);
      
          // 組合reducer對(duì)象
          const reducer = {
            [`${componentName}Reducer`]: req(path).default
          };
      
          return Object.assign({}, obj, reducer);
        };
      
        // 從CONTEXT路徑數(shù)組中組合成reducer對(duì)象返回
        const getReducers = ctx => ctx.keys().reduce(importReducer(ctx), {});
        return getReducers(CONTEXT);
      };
      
      export const autoCombineSaga = (path = "../") => {
        let CONTEXT = getContext(path, "saga");
        // 獲取完組合成reducer對(duì)象
        const forkSaga = req => path => {
          //從路徑中獲取reducer name
          // output:[0: "demo",groups: undefined,index: 7,input: "./demo/demo.reducer.js"]
          const [componentName] = path.match(/\w+(?=\/saga\.js$)/);
          return fork(req(path).default);
        };
      
        // 從CONTEXT路徑數(shù)組中組合成reducer對(duì)象返回
        const getSagas = ctx => ctx.keys().map(forkSaga(ctx));
        return getSagas(CONTEXT);
      };
      

      大家有沒(méi)有發(fā)現(xiàn)其實(shí)上面已經(jīng)配置好了immutable.js,所以我們就可以直接在reduer文件里面使用immutable對(duì)象了,如下所示:

      reducer.js

      import { handleActions } from "redux-actions";
      import { authTypes } from "./action";
      import moment from "moment";
      import { Map, fromJS, merge } from "immutable";
      
      const initState = fromJS({
        user: null,
        token: ""
      });
      
      const authReducer = handleActions(
        {
          [authTypes.AUTH_SUCCESS]: (state, action) => {
            return state.merge({
              user: action.data.user,
              token: action.data.token
            });
          },
          [authTypes.SIGN_OUT]: (state, action) => {
            return state.merge({
              user: null,
              token: ""
            });
          }
        },
        initState
      );
      
      export default authReducer;
      

      這樣就完成了redux和immutable.js的配置了,下面我們來(lái)配置antd。

      使用next-plugins來(lái)配置antd和hiynn-design

      ant-design
      antd 就不需要我多說(shuō)明了吧,國(guó)內(nèi)頂級(jí)大廠的杰出之作。

      hiynn-design
      hiynn-design是我公司(海云)前(我)端(創(chuàng))團(tuán)(建)隊(duì)(的)創(chuàng)建的UI庫(kù),分為標(biāo)準(zhǔn)化組件和可視化組件。

      同樣的我們?cè)趎ext.js的example里面找到:with-ant-design-less 我們就100%參考這個(gè)實(shí)例來(lái)配置antd,首先我們來(lái)添加下相關(guān)依賴包:

      yarn add @zeit/next-css @zeit/next-sass @zeit/next-less next-compose-plugins less-vars-to-js next-images 
      
      yarn add babel-plugin-import @babel/plugin-proposal-decorators @babel/plugin-proposal-do-s @babel/plugin-proposal-class-properties

      回過(guò)頭來(lái)我們?cè)賮?lái)看看next-plugins包含那些插件,如下所示:

      image.png

      這里就不一一詳細(xì)說(shuō)明了,我們只舉幾個(gè)重要的安裝包來(lái)說(shuō)明下。

      next-images
      在SPA項(xiàng)目里面我們使用import或者require來(lái)加載圖片,但是next.js不是那么簡(jiǎn)單的,它會(huì)提供你一個(gè)public文件夾來(lái)放靜態(tài)圖片,然后寫上絕對(duì)地址,這樣一來(lái)動(dòng)態(tài)添加圖片就變得麻煩,因此就有next-images這個(gè)依賴包的出現(xiàn)了,這個(gè)包的作用是讓你像import require那樣引入你的圖片。

      next-compose-plugins
      當(dāng)我們的next.config.js文件需要同時(shí)配置多個(gè)包的時(shí)候就會(huì)讓每個(gè)單獨(dú)配置的包分散開(kāi)了,這樣不利于維護(hù),因此就出現(xiàn)了next-compose-plugins把各個(gè)分散的包集合在一起,具體的請(qǐng)查看next-compose-plugins

      接著我們就按照with-ant-design-less來(lái)配置.babelrc和next.config.js文件,這里我們同時(shí)支持了ant-design和hiynn-design,詳細(xì)代碼如下:

      .babelrc

      {
        "presets": [
          "@babel/preset-react", "next/babel"
        ],
        "plugins": [
          "@babel/plugin-proposal-do-s",
          [
            "@babel/plugin-proposal-decorators",
            {
              "legacy": true
            }
          ],
          ["@babel/plugin-proposal-class-properties", {
            "loose": true
          }],
          //按需加載antd樣式
          [
            "import", {
              "libraryName": "antd",
              "style": true
            },
            "antd"
          ],
          //按需加載hiynnd樣式
          [
            "import",
            {
              "libraryName": "hiynn-design",
              "style": true
            },
            "hiynn-design"
          ]
        ]
      }
      

      next.config.js

      const withCss = require("@zeit/next-css");
      const withSass = require("@zeit/next-sass");
      const withPlugins = require("next-compose-plugins");
      const withLess = require("@zeit/next-less");
      const lessToJS = require("less-vars-to-js");
      const fs = require("fs");
      const path = require("path");
      const withImages = require("next-images");
      
      // Where your antd-custom.less file lives
      const themeVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, "./src/assets/styles/antd-custom.less"), "utf8"));
      
      module.exports = withPlugins([withCss, withSass, withLess, withImages], {
        cssLoaderOptions: {
          importLoaders: 1
        },
        lessLoaderOptions: {
          javascriptEnabled: true,
          modifyVars: themeVariables // make your antd custom effective
        },
        webpack: (config, { isServer }) => {
          if (isServer) {
            const antStyles = /antd\/.*?\/style.*?/;
            const hiynnStyles = /hiynn-design\/.*?\/style.*?/;
            const origExternals = [...config.externals];
            config.externals = [
              (context, request, callback) => {
                if (request.match(antStyles) || request.match(hiynnStyles)) {
                  return callback();
                }
                if (typeof origExternals[0] === "function") {
                  origExternals[0](context, request, callback);
                } else {
                  callback();
                }
              },
              ...(typeof origExternals[0] === "function" ? [] : origExternals)
            ];
            config.module.rules.push(
              {
                test: antStyles,
                use: "null-loader"
              },
              {
                test: hiynnStyles,
                use: "null-loader"
              }
            );
          }
          return config;
        }
      });
      

      請(qǐng)注意,Next.js無(wú)法使用css-loader。 請(qǐng)參閱官方頁(yè)面上的警告
      警告:不建議添加加載程序以支持新的文件類型(css,less,svg等),因?yàn)橹挥锌蛻舳舜a通過(guò)webpack捆綁在一起,因此在初始服務(wù)器渲染中不起作用。 Babel插件是一個(gè)不錯(cuò)的選擇,因?yàn)樗鼈冊(cè)诜?wù)器/客戶端渲染之間一致地應(yīng)用

      這也算是配置next.js中的一個(gè)小插曲吧,大家知道就好,因?yàn)槲覀兩厦嬉呀?jīng)解決了這個(gè)問(wèn)題。

      Bug:Module parse failed: Unexpected character '@'

      image

      然后我們運(yùn)行起來(lái)試試,報(bào)了一個(gè)bug!我們明明已經(jīng)按照with-ant-design-less配置好了同時(shí)支持ant-design和hiynn-design為什么還報(bào)錯(cuò)?

      接著我就找問(wèn)題原因,在segmentfault和next-plugins 的issues 上面提問(wèn),最后發(fā)現(xiàn)next.js不支持.pcss,因此我就把hiynn-design的庫(kù)從.pcss全部變成了.scss,這樣重新編譯并打包發(fā)布并安裝,運(yùn)行起來(lái)就沒(méi)這個(gè)錯(cuò)了,但是又有個(gè)新的bug,真的是一波未平一波又起??!

      Bug:SyntaxError:Unexpected string

      image

      接著我就又找問(wèn)題原因,同樣我又在segmentfault和next-plugins的issues上面提問(wèn),最后發(fā)現(xiàn)是因?yàn)槲覂蓚€(gè)庫(kù)的.babelrc文件里面按需加載的libraryDirecory不一致導(dǎo)致的,hiynn-design庫(kù)使用的libraryDirecory是'es',而next.js項(xiàng)目使用的libraryDirecory是'lib',然后我統(tǒng)一了一下兩個(gè)libraryDirecory就沒(méi)問(wèn)題了,代碼如下:

      [
        "import", {
          "libraryName": "antd",
          "style": true
        },
        "antd"
      ],

      Bug:SyntaxError:Invalid or unexpected token

      image.png
      這個(gè)問(wèn)題是因?yàn)閍ntd .less文件后綴引起的,在next.config.js加上下面這段代碼就OK了

      next.config.js

      const withCss = require("@zeit/next-css");
      const withSass = require("@zeit/next-sass");
      const withPlugins = require("next-compose-plugins");
      const withLess = require("@zeit/next-less");
      const lessToJS = require("less-vars-to-js");
      const fs = require("fs");
      const path = require("path");
      const withImages = require("next-images");
      
      // Where your antd-custom.less file lives
      const themeVariables = lessToJS(fs.readFileSync(path.resolve(__dirname, "./src/assets/styles/antd-custom.less"), "utf8"));
      + require.extensions[".less"] = () => {};
      module.exports = withPlugins([withCss, withSass, withLess, withImages], {
        cssLoaderOptions: {
          importLoaders: 1
        },
        lessLoaderOptions: {
          javascriptEnabled: true,
          modifyVars: themeVariables // make your antd custom effective
        },
        webpack: (config, { isServer }) => {
          if (isServer) {
            const antStyles = /antd\/.*?\/style.*?/;
            const hiynnStyles = /hiynn-design\/.*?\/style.*?/;
            const origExternals = [...config.externals];
            config.externals = [
              (context, request, callback) => {
                if (request.match(antStyles) || request.match(hiynnStyles)) {
                  return callback();
                }
                if (typeof origExternals[0] === "function") {
                  origExternals[0](context, request, callback);
                } else {
                  callback();
                }
              },
              ...(typeof origExternals[0] === "function" ? [] : origExternals)
            ];
            config.module.rules.push(
              {
                test: antStyles,
                use: "null-loader"
              },
              {
                test: hiynnStyles,
                use: "null-loader"
              }
            );
          }
          return config;
        }
      });
      

      最后這些問(wèn)題解決后我們?cè)龠\(yùn)行就不再報(bào)錯(cuò)了,運(yùn)行正常!雖然我寫這篇文章只用了2個(gè)小時(shí),但是解決這些問(wèn)題我足足花了一個(gè)多月。

      總結(jié)

      1、next.js對(duì)css-loader支持不友好,應(yīng)該是所有node.js基于后臺(tái)的通病了
      2、配置redux和immutable網(wǎng)上有現(xiàn)成的案例可以根據(jù)這些案例進(jìn)行配置
      3、配置antd和hiynnd是最辛苦的,雖然最后成功了
      4、postcss一般做為輔助sass或者less庫(kù)使用最好,而不要單獨(dú)使用,比如我的hiynn-design庫(kù)一開(kāi)始使用的全是.pcss結(jié)尾,然后就變成.scss。

      參考

      less、sass和postcss總結(jié)
      next-plugins
      ModuleParseError: Module parse failed: Unexpected character '@'
      SyntaxError: Unexpected string
      nextjs-starter-kit
      nextjs-starter
      嗶哩嗶哩(B站)的前端之路
      PostCSS深入學(xué)習(xí): PostCSS和Sass、Stylus或LESS一起使用
      Next.js 使用指南2-路由與加載
      next-images
      next.js 采坑錄(服務(wù)端渲染)

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多