<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>

          【總結(jié)】2017- 不要再寫滿屏import導(dǎo)入啦!

          共 8617字,需瀏覽 18分鐘

           ·

          2024-04-15 18:50

          作者:tager
          原文:https://juejin.cn/post/7344571285848768524

          密密麻麻的import語句不僅僅是一種視覺上的沖擊,更是對代碼組織結(jié)構(gòu)的一種考驗。

          我們是如何做到讓import“占領(lǐng)滿屏“的了,又該如何優(yōu)雅地管理這些import語句呢?

          本文將從產(chǎn)生大量import語句的原因、可能帶來的問題以及如何優(yōu)化和管理import語句幾個角度來進行探討。

          import是如何“占領(lǐng)滿屏“的?

          拒絕使用模塊重導(dǎo)(Re-export

          模塊重導(dǎo)是一種通用的技術(shù)。在騰訊、字節(jié)、阿里等各大廠的組件庫中都有大量使用。

          如:字節(jié)的arco-design組件庫中的組件:github.com/arco-design…[1]

          通過重導(dǎo)在comonents/index.tsx文件暴露所有組件,在使用時一個import就可以使用N個組件了。

          // 不使用重導(dǎo)
          import Modal from '@arco-design/web-react/es/Modal'
          import Checkbox from '@arco-design/web-react/es/Checkbox'
          import Message from '@arco-design/web-react/es/Message'
          ...

          // 使用模塊重導(dǎo)
          import { Modal, Checkbox, Message} from '@arco-design/web-react'

          Re-export一般用于收攏同類型的模塊、一般都是以文件夾為單位,如components、routes、utils、hooks、stories等都通過各自的index.tsx暴露,這樣就能極大程度的簡化導(dǎo)入路徑、提升代碼可讀性、可維護性

          Re-export的幾種形式

          1. 直接重導(dǎo)出

          直接從另一個模塊重導(dǎo)出特定的成員。

          export { foo, bar } from './moduleA';

          2. 重命名并重導(dǎo)出(含默認(rèn)導(dǎo)出)

          從另一個模塊導(dǎo)入成員,可能會重命名它們,然后再導(dǎo)出。

          默認(rèn)導(dǎo)出也可以重命名并重導(dǎo)出

          // 通過export導(dǎo)出的
          export { foo as newFoo, bar as newBar } from './moduleA';
          // 通過export default導(dǎo)出的
          export { default as ModuleDDefault } from './moduleD';

          3. 重導(dǎo)出整個模塊(不含默認(rèn)導(dǎo)出)

          將另一個模塊的所有導(dǎo)出成員作為單個對象重導(dǎo)出。(注意:整個導(dǎo)出不會包含export default)

          export * from './moduleA';

          4. 收攏、結(jié)合導(dǎo)入與重導(dǎo)出

          首先導(dǎo)入模塊中的成員,然后使用它們,最后將其重導(dǎo)出。

          import { foo, bar } from './moduleA';
          export { foo, bar };

          通過這些形式,我們可以靈活地組織和管理代碼模塊。每種形式都有其適用場景,選擇合適的方式可以幫助我們構(gòu)建出更清晰、更高效的代碼結(jié)構(gòu)。

          從不使用require.context

          require.context 是一個非常有用的功能,它允許我們動態(tài)地導(dǎo)入一組模塊,而不需要顯式地一個接一個地導(dǎo)入。

          只需一段代碼讓你只管增加文件、組件,將自動收攏重導(dǎo)。

          在項目路由、狀態(tài)管理等固定場景下極其好使(能提效、盡可能避免了增加一個配置要動N個文件的情況)

          尤其是在配置路由時、產(chǎn)生大批量的import(多少個頁面就得導(dǎo)入多少個import??)

          // 不使用require.context
          import A form '@/pages/A'
          import B form '@/pages/B'
          ...

          // routes/index.ts文件統(tǒng)一處理
          // 創(chuàng)建一個context來導(dǎo)入routes目錄下所有的 .ts 文件
          const routesContext = require.context('./routes'false, /.ts$/);
          const routes = [];
          // 遍歷 context 中的每個模塊
          routesContext.keys().forEach(modulePath => {
            // 獲取模塊的導(dǎo)出
            const route = routesContext(modulePath);
            // 獲取組件名稱【如果需要話】,例如:從 "./Header.ts" 提取 "Header"
            // const routeName = modulePath.replace(/^./(.*).\w+$/, '$1');
            // 將組件存儲在組件對象中
            routes.push(route.default || route)
          });

          export default routes;

          在大項目、多路由的情況下,使用 require.context 在處理路由導(dǎo)入上大有可為

          從不使用import動態(tài)導(dǎo)入

          動態(tài)import也能實現(xiàn)類似require.context的功能、動態(tài)收攏模塊。關(guān)于import動態(tài)導(dǎo)入的更多內(nèi)容可以看下這篇文章內(nèi)的介紹《如何在Vite5?React?Ts項目中優(yōu)雅的使用Mock數(shù)據(jù)?》[2]

          對ProvidePlugin不感興趣

          webpack.ProvidePlugin是個好東西,但也不能濫用

          項目中用到的變量/函數(shù)/庫或工具,只要配置后就可以在任何地方使用了。

          相信我--看完這個示例,如果你沒用過、那你肯定會迫不及待的想要嘗試了??

          const webpack = require('webpack');

          module.exports = {
            // 其他配置...
            plugins: [
              new webpack.ProvidePlugin({
                React'react',
                _'lodash',
                dayjs'dayjs',
                // 假設(shè)項目中自己定義的utils.js在src目錄下
                Utils: path.resolve(__dirname, 'src/utils.js')
          })
              })
            ]
            // 其他配置...
          };

          現(xiàn)在你可以在任何地方使用 dayjs、lodash、Utils等,而不需要導(dǎo)入它

          小結(jié):

          • webpack.ProvidePlugin是一個強大的工具,它可以幫助我們減少重復(fù)的導(dǎo)入語句,使代碼更加干凈整潔。但是,它不會減少構(gòu)建大小,因為這些庫仍然會被包含在你的最終打包文件中。正確使用這個插件可以提高開發(fā)效率,但需要謹(jǐn)慎使用,以避免隱藏依賴關(guān)系,導(dǎo)致代碼難以理解和維護。
          • 對于需要按需加載的模塊或組件,考慮使用動態(tài) import() 語法,這樣可以更有效地控制代碼的加載時機和減小打包體積。
          • 謹(jǐn)慎使用 ProvidePlugin,只為那些確實需要在多個地方使用的模塊配置全局變量,以避免不必要的代碼打包。

          另外,如果是Vite項目可以使用vite-plugin-inject代替ProvidePlugin的功能

          // 配置
          import inject from 'vite-plugin-inject'// 實測暫不可用,有替代方案再更新
          ...
          plugins: [
          inject({
            // 鍵是你想要提供的全局變量,值是你要提供的模塊
            dayjs: 'dayjs'// 例如,這將在全局范圍內(nèi)提供 'dayjs',可以通過 dayjs 訪問
            // 你可以繼續(xù)添加其他需要全局提供的模塊
          }),
          ]
          ...

          如果使用了TS,記得配置下類型:

          // globals.d.ts文件 處理全局類型
          import dayjs from 'dayjs';
          declare global {
            const dayjs: typeof dayjs;
          }

          // tsconfig.json文件 也配置一下

          "compilerOptions": { 
          // 編譯選項... 
          }, 
          "include": [ "src/**/*""globals.d.ts" // 確保 TypeScript 包括這個文件 ] 
          }

          大量使用Typescript導(dǎo)入類型

          在TS項目中,滿屏import肯定少不了TS的份。但如果合理配置,必定能急劇減少import的導(dǎo)入

          這里介紹下自己在項目中使用最多的方法:TS命名空間。有了它既能讓類型模塊化,更過分的是在使用時可以直接不導(dǎo)入類型??。

          同樣,它和ProvidePlugin一樣炸裂,可以直接滅掉import導(dǎo)入。


          使用示例:

          // accout.ts
          declare namespace IAccount {
            type IList<T = IItem> = {
              count: number
              list: T[]
            }
            interface IUser {
              id: number;
              name: string;
              avatar: string;
            }
          }

          // 任意文件直接使用,無需導(dǎo)入
          const [list, setList] = useState<IAccount.IList|undefined>();
          const [user, setUser] = useState<IAccount.IUser|undefined>();

          注意??eslint可能需要配置下開啟??使用命名空間

          《不去充分利用bable特性》

          React似乎也意識到不妥:在17版本之前,由于jsx的特性每個組件都需要明文引入import React from 'react',但在這之后由編譯器自行轉(zhuǎn)換,無需引入 React。如果你使用的React17之前的版本也可以通過修改babel達到這個目的,更多細節(jié)可參考React官網(wǎng)[3],有非常詳細的說明。(也提供了自動去除引入的腳本)

          其它

          1. 設(shè)置webpack、ts別名。

          既能縮短導(dǎo)入路徑、也能更有語義化

          resolve: {
            alias: {
              "@src": path.resolve(__dirname, 'src/'),
              "@components": path.resolve(__dirname, 'src/components/'),
              "@utils": path.resolve(__dirname, 'src/utils/')
            }
          }

          // 使用別名前
          import MyComponent from '../../../../components/MyComponent';

          // 使用別名后
          import MyComponent from '@components/MyComponent';

          2. 設(shè)置格式化prettier.printWidth

          值設(shè)置的太小可能會導(dǎo)致頻繁換行、給夠難以閱讀。其值在120較為合適吧(看團隊實際的使用情況)。

          {
            "printWidth"120,
            ...
          }

          3. 按條件動態(tài)全局加載組件

          在入口文件引入全局組件,使用require.ensure或import根據(jù)條件動態(tài)加載組件,既能便于維護、減少引用、也能減少性能開銷

          // 異步加載全局彈窗,減少性能開銷
          Vue.component('IMessage'function (resolve{
            // 指定條件全局加載,無需在具體頁面中引用
            if (/^\/pagea|pageb/.test(location.pathname)) {
            require.ensure(['./components/message/index.vue'], function({
              resolve(require('./components/message/index.vue'));
            });
            }
          });

          4. babel-plugin-import的使用

          babel-plugin-import不是直接減少 import 的數(shù)量,而是通過優(yōu)化 import 語句來減少打包體積,提高項目的加載性能。這對于使用了大型第三方庫的項目來說是一個非常有價值的優(yōu)化手段。

          arco-design為例:

          // .bablerc配置
          {
            "plugins": [
              ["import", {
                "libraryName""@arco-design/web-react",
                "libraryDirectory""es"// 或者 "lib",依賴于具體使用的模塊系統(tǒng)
                "style"true // 加載 CSS
              }, "@arco-design/web-react"]
            ]
          }
          // 這個配置告訴 babel-plugin-import 自動將類似 import { Button } from '@arco-design/web-react'; 的導(dǎo)入語句轉(zhuǎn)換為按需導(dǎo)入的形式,并且加載對應(yīng)的 CSS 文件。
          // 業(yè)務(wù)中使用
          import { Button } from '@arco-design/web-react';
          // 將被bable編譯成
          import Button from '@arco-design/web-react/es/button';
          import '@arco-design/web-react/es/button/style/css.js'// 如果 style 配置為 true

          總結(jié)

          導(dǎo)致import占滿全屏的原因有很多。但不用模塊重導(dǎo)、require.context、import動態(tài)導(dǎo)入、webpack.ProvidePlugin等手段,一定會讓我們寫出滿屏的import????????。

          只有想不到的,沒有做不到的。只要你想、相信就一定能如愿以償。

          參考資料
          [1]

          https://github.com/arco-design/arco-design/blob/main/components/index.tsx: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Farco-design%2Farco-design%2Fblob%2Fmain%2Fcomponents%2Findex.tsx

          [2]

          https://juejin.cn/post/7344571292354838591: https://juejin.cn/post/7344571292354838591

          [3]

          https://zh-hans.legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html: https://link.juejin.cn?target=https%3A%2F%2Fzh-hans.legacy.reactjs.org%2Fblog%2F2020%2F09%2F22%2Fintroducing-the-new-jsx-transform.html

          瀏覽 163
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          10點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  婷婷亚洲丁香色五月 | 激情毛片网 | 欧美bbb高朝 | 久久三级精品视频 | 大香蕉综合网站 |