<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # 簡介 中文官網:https://webpack.docschina.org/ 中文社區:https://github.com/webpack-china/webpack.js.org Webpack 始于 2012 年,由 Tobias Koppers 發起,用于解決當時現有工具未解決的的一個難題:**構建復雜的單頁應用程序 (SPA)。** # webpack 4 基礎 webpack 4 中零配置的概念適用于: * `entry` point(入口點) 默認為 `./src/index.js ` * `output`(輸出) 默認為 `./dist/main.js` * production (生產) 和 development (開發) 模式 (無需為生產和開發環境創建2個單獨的配置) 這就夠了。 但是對于在 webpack 4 中使用 loader (加載器),您仍然需要創建配置文件。 1. 默認打包后的文件是被壓縮的 2. 新建配置文件(進行手動配置,**默認配置文件**名為:`webpack.config.js` 或者 `webpackfile.js`) ``` let path=require('path') module.exports = { mode:'development', //代表為開發模式 也可以是生產模式 production(打包后的文件為壓縮模式) entry:'./src/index.js', //入口文件 output:{ filename:'bundle.js', //打包輸出的文件名 path:path.resolve(__dirname,'dist') // 打包輸出的路徑(必須是絕對路徑) } } ``` 3. 自定義配置文件名 ``` npx webpack --config webpack.config.custom.js ``` # WebPack 是什么 1、一個打包工具 2、一個模塊加載工具 3、各種資源都可以當成模塊來處理 4、網站 [http://webpack.github.io/](https://link.jianshu.com?t=http%3A%2F%2Fwebpack.github.io%2F) 如今,越來越多的JavaScript代碼被使用在頁面上,我們添加很多的內容在瀏覽器里。如何去很好的組織這些代碼,成為了一個必須要解決的難題。 對于模塊的組織,通常有如下幾種方法: ????1、通過書寫在不同文件中,使用 script 標簽進行加載 ????2、CommonJS進行加載(NodeJS 就使用這種方式) ????3、AMD 進行加載(require.js 使用這種方式) ????4、ES6 模塊 > **思考:為什么只有****JS****需要被模塊化管理,前端的很多預編譯內容,不需要管理嗎?** ![](https://upload-images.jianshu.io/upload_images/1419656-91e4422875a988ff.png?imageMogr2/auto-orient/strip|imageView2/2/w/1190/format/webp) 基于以上的思考,WebPack 項目有如下幾個目標: ????? 將依賴樹拆分,保證按需加載 ????? 保證初始加載的速度 ????? 所有靜態資源可以被模塊化 ????? 可以整合第三方的庫和模塊 ????? 可以構造大系統 ## WebPack的特點 1、豐富的插件,方便進行開發工作 2、大量的加載器,包括加載各種靜態資源 3、代碼分割,提供按需加載的能力 4、發布工具 ## WebPack的優勢 ???? ? webpack 是以 commonJS 的形式來書寫腳本滴,但對 AMD/CMD 的支持也很全面,方便舊項目進行代碼遷移。 ? 能被模塊化的不僅僅是 JS 了。 ? 開發便捷,能替代部分 grunt/gulp 的工作,比如打包、壓縮混淆、圖片轉 base64 等。 ? 擴展性強,插件機制完善,特別是支持 React 熱插拔(見 react-hot-loader )的功能讓人眼前一亮。 ## 模塊化打包工具 webpack是一種模塊化的工具,每個資源對于webpack來講都是一個模塊,模塊之間的引用,它們之間存在的關系,webpack都可以處理好。 ????1、兼容多種JS模塊規范 ????2、更好地打包靜態資源 ????3、更好地處理模塊間的關系 > [引用 Node 模塊和 NPM 模塊](https://webpack.toobug.net/zh-cn/chapter2/umd.html) # 深入了解 webpack ## 流程細節 Webpack 的構建流程可以分為以下三大階段: 1. 初始化:啟動構建,讀取與合并配置參數,加載 Plugin,實例化 Compiler。 2. 編譯:從 Entry 發出,針對每個 Module 串行調用對應的 Loader 去翻譯文件內容,再找到該 Module 依賴的 Module,遞歸地進行編譯處理。 3. 輸出:對編譯后的 Module 組合成 Chunk,把 Chunk 轉換成文件,輸出到文件系統。 Webpack 打包,最基本的實現方式,是將所有的模塊代碼放到一個對象(或數組)里,通過屬性名(數組ID)對應的路徑查找模塊,如下所示,可以發現入口`index.js`的代碼是放在對應路徑值中,其它 `a.js` 和 `b.js` 的代碼分別放在了屬性名為路徑名的對應值中,而 webpack 引用的時候,主要通過`__webpack_require__`的方法引用不同索引的模塊。 ``` /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function // 定義了一個 require 函數 /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { // installedModules 模塊緩存 /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); // 啟動程序 /******/ }) /************************************************************************/ /******/ ({ /***/ "./src/a.js": /*!******************!*\ !*** ./src/a.js ***! \******************/ /*! exports provided: default */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _b__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./b */ \"./src/b.js\");\n\n\n\n\nconsole.log(\"b file value: \"+ _b__WEBPACK_IMPORTED_MODULE_0__[\"value\"]);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ('a'+ _b__WEBPACK_IMPORTED_MODULE_0__[\"value\"]);\n\n//# sourceURL=webpack:///./src/a.js?"); /***/ }), /***/ "./src/b.js": /*!******************!*\ !*** ./src/b.js ***! \******************/ /*! exports provided: value */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"value\", function() { return value; });\n\n\nconst value = 'b';\n\n//# sourceURL=webpack:///./src/b.js?"); /***/ }), /***/ "./src/index.js": /*!**********************!*\ !*** ./src/index.js ***! \**********************/ /*! no exports provided */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a */ \"./src/a.js\");\n\n\nconsole.log(\"Hello Webpack! \" + _a__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n//# sourceURL=webpack:///./src/index.js?"); /***/ }) /******/ }); ``` ## 與Grunt、Gulp、browserify的區別 * Grunt/Gulp 1. Grunt/Gulp 工具鏈、構建工具,可以配合各種插件做js壓縮,css壓縮,less編譯 替代手工實現自動化工作 2. 自動化 3. 提高效率用 4. 可以配置 seajs、requirejs 甚至 webpack的插件。?? * webpack 模塊化打包 1. webpack 是一種模塊化打包工具; 2. 能夠將css、js、image打包為一個JS文件; 3. 更智能的模塊打包; 4. 更豐富的插件、模塊加載器。 * seajs / require 是一種在線"編譯" 模塊的方案,相當于在頁面上加載一個 CMD/AMD 解釋器。這樣瀏覽器就認識了 define、exports、module 這些東西。也就實現了模塊化。 * browserify 是一個預編譯模塊的方案,相比于上面 ,這個方案更加智能。 ## gulp 結合 Webpack ~~~ import gulpWebpack from 'webpack-stream' ~~~ [https://github.com/shama/webpack-stream](https://github.com/shama/webpack-stream) ## WebPack的配置 每個項目下都可能會有 webpack 配置或是其他形式(如 create-react-app),用來告訴 webpack 它需要做什么。 下面是一個例子: ``` const webpack = require('webpack'); const commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js'); module.exports = { ??? //插件項 ??? plugins:[commonsPlugin], ??? //頁面入口文件配置 ??? entry:{ ??????? index : './src/index.js' ??? }, ??? //入口文件輸出配置 ??? output:{ ??????? path: 'dist/js/page', ??????? filename: '[name].js' ??? }, ??? module:{ ??????? // 加載器配置 ??????? loaders:[ { test: /\.eot$|\.svg$|\.ttf$|\.woff$/, // 字體圖標最終會以 base64 的方式被打包到 CSS 中 use: [ { loader: 'url-loader' } ] }, { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1 } }, { loader: 'less-loader', options: { noIeCompat: true } } ] }, { test: /\.js$/, include, exclude, use: "babel-loader", }, { test: /\.(png|jpg|gif|svg)$/, loader: 'file-loader' } ??????? ] ??? }, ??? // 其它解決方案配置 ??? resolve:{ ??????? extensions: [ '.js', '.json', '.scss'], ??????? alias:{ ??????????? AppStore : 'js/stores/AppStores.js', ??????????? ActionType : 'js/actions/ActionType.js', ??????????? AppAction : 'js/actions/AppAction.js' ??????? } ??? } }; ``` 1. `plugins` 是插件項,這里我們使用了一個 `CommonsChunkPlugin` 的插件,它用于提取多個入口文件的公共腳本部分,然后生成一個 `common.js` 來方便多頁面之間進行復用。 2. `entry` 是頁面入口文件配置,`output` 是對應輸出項配置 (即入口文件最終要生成什么名字的文件、存放到哪里) 3. `module.loaders` 是最關鍵的一塊配置。它告知 webpack 每一種文件都需要使用什么加載器來處理。 **所有加載器需要使用 npm 加載** 4. 最后是 `resolve` 配置,配置查找模塊的路徑和擴展名和別名(方便書寫) ## Loaders 加載器 webpack 本身只能解析`.js`和`.json`文件,loader 是將其他類型轉成**模塊**, 以添加到依賴圖中。它接收兩個屬性,分別是`test`和`use`, 前者是一個**正則表達式**, 匹配需要被 loader 轉換的文件格式,后者是**使用的 loader 名**. ``` module.exports = { //... module: { rules: [ { test: /\.js$/, exclude: /node_modules/, // 不解析 node_modules include: path.resolve('src'), // 只解析 src 目錄下的文件,兩者寫其一即可 use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'] } } } ] } } ``` 對于 loader, 還有兩種使用用方式,分別是**內聯**和**CLI**, 不過都不常用. ``` // 內聯 loader import Styles from 'style-loader!css-loader?modules!./styles.css'; // CLI loader webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader' ``` ## webpack 常用命令: ``` webpack??????? # 最基本的啟動webpack命令 webpack -w? # 提供watch方法,實時進行打包更新 webpack -p?? # 對打包后的文件進行壓縮 webpack -d?? # 提供SourceMaps,方便調試 webpack --config pathToConfigFile # 使用 --config 參數傳入路徑 webpack --colors # 輸出結果帶彩色,比如:會用紅色顯示耗時較長的步驟 webpack --profile # 輸出性能數據,可以看到每一步的耗時 webpack --display-modules # 默認情況下node\_modules下的模塊會被隱藏,加上這個參數可以顯示這些被隱藏的模塊 ``` ## 入口文件配置:entry 參數 entry 可以是字符串(單入口),可以是數組(多入口),但為了后續發展,請務必使用 object,因為 這個 object 中的 key 在 webpack 里相當于此入口的 name,既可以后續用來拼生成文件的路徑,也可以用來作為此入口的唯一標識。我推薦的形式是這樣的: ``` entry: {? ? // pagesDir 是前面準備好的入口文件集合目錄的路徑 ? 'alert/index':path.resolve(pagesDir, `./alert/index/page`), ? 'index/login':path.resolve(pagesDir, `./index/login/page`), ? 'index/index':path.resolve(pagesDir, `./index/index/page`), }, ``` 對照我的腳手架項目 [webpack-seed](https://link.jianshu.com?t=https%3A%2F%2Fgithub.com%2FArray-Huang%2Fwebpack-seed) 的文件目錄結構,就很清楚了: ``` ├─src # 當前項目的源碼 ???├─pages # 各個頁面獨有的部分,如入口文件、只有該頁面使用到的 css、模板文件等 ???│? ├─alert # 業務模塊 ???│? │? └─index # 具體頁面 ???│? ├─index # 業務模塊 ???│? │? ├─index # 具體頁面 ???│? │? └─login # 具體頁面 ``` 由于每一個入口文件都相當于 entry 里的一項,因此這樣一項一項地來寫實在是有點繁瑣,我就稍微寫了點代碼來拼接這 entry: ``` var?pageArr = [ ??? 'index/login', ??? 'index/index', ??? 'alert/index', ]; var?configEntry = {}; pageArr.forEach((page) => { ???configEntry[page] = path.resolve(pagesDir, page +'/page'); }); ``` ## 輸出文件:`output`參數 ?`output` 參數告訴 webpack 以什么方式來生成/輸出文件,值得注意的是,與`entry` 不同,`output`相當于一套規則,所有的入口都必須使用這一套規則,不能針對某一個特定的入口來制定 output 規則。`output`參數里有這幾個子參數是比較常用的:path、publicPath、filename、chunkFilename,這里先給個 [webpack-seed](https://github.com/Array-Huang/webpack-seed) 中的示例: ``` output: { ?????path: buildDir, // var buildDir = path.resolve(__dirname, './build'); ?????publicPath: '../../../../build/', ?????filename: '[name]/entry.js',??? // [name] 表示 entry 每一項中的 key,用以批量指定生成后文件的名稱 ?????chunkFilename: '[id].bundle.js', }, ``` ### `path` path 參數表示生成文件的根目錄,需要傳入一個**絕對路徑**。 path 參數和后面的 filename 參數共同組成入口文件的完整路徑。 ### `publicPath` `publicPath`參數表示的是一個 URL 路徑(指向生成文件的根目錄),用于生成 css / js /圖片/字體文件等資源的路徑,以確保網頁能正確地加載到這些資源。 ?publicPath 參數跟 path 參數的區別是:path 參數其實是針對本地文件系統的,而 publicPath 則針對的是瀏覽器;因此,publicPath 既可以是一個相對路徑,如示例中的`../../../../build/,`也可以是一個絕對路徑如`http://www.xxxxx.com/`。 一般來說,我還是更推薦相對路徑的寫法,這樣的話整體遷移起來非常方便。那什么時候用絕對路徑呢? 其實也很簡單,當你的 html 文件跟其它資源放在不同的域名下的時候,就應該用絕對路徑了,這種情況非常多見于 CDN 和后端渲染模板的場景。 ### `filename` filename 屬性表示的是如何命名生成出來的入口文件,規則有以下三種: 1. `[name]`:指代入口文件的`name`,也就是上面提到的`entry`參數的 `key`,因此,我們可以在`name`里利用 `/`,即可達到控制文件目錄結構的效果。 2. `[hash]`:指代**本次編譯**的一個`hash`版本(an hash of the compilation. See the [Caching guide](https://devdocs.io/webpack/guides/caching) for details.),值得注意的是,只要是在同一次編譯過程中生成的文件,這個 `[hash]` 的值就是一樣的;在緩存的層面來說,相當于一次全量的替換。 3. `[chunkhash]`:指代的是當前 chunk 的一個 hash 版本,也就是說,在同一次編譯中,每一個 chunk 的 hash 都是不一樣的;而在兩次編譯中,如果某個 chunk 根本沒有發生變化,那么該 chunk 的 hash 也就不會發生變化。這在緩存的層面上來說,就是把緩存的粒度精細到具體某個 chunk,只要 chunk 不變,該 chunk 的瀏覽器緩存就可以繼續使用。 下面來說說如何利用 `filename` 參數和 `path` 參數來設計入口文件的目錄結構,如示例中的 `path:buildDir, // var buildDir = path.resolve(__dirname, './build');` 和 `filename: '[name]/entry.js'`, 那么對于`key`為 `'index/login'` 的入口文件,生成出來的路徑就是 `build/index/login/entry.js` 了,怎么樣,是不是很簡單呢? ### chunkFilename `chunkFilename`參數與 `filename` 參數類似,都是用來定義生成文件的命名方式的,只不過,`chunkFilename`參數指定的是除入口文件外的`chunk`(這些`chunk`通常是由于 webpack 對代碼的優化所形成的,比如因應實際運行的情況來異步加載)的命名。 # chunk(分片) webpack也提供了代碼分片機制,使我們能夠將代碼拆分后進行異步加載。 > 值得注意的是,webpack 對代碼拆分的定位僅僅是為了解決文件過大,無法并發加載,加載時間過長等問題,并不包括公共代碼提取和復用的功能。對公共代碼的提取將由`CommonChunks`插件來完成。 要使用webpack的分片功能,首先需要定義“分割點”,即代碼從哪里分割成兩個文件。具體的方式有兩種: `require.ensure`和 AMD `require`兩種方式,來建立分割點,代碼在此處被分片。 ~~~ var a=require('./a'); a.sayHello(); require.ensure(['./b'], function(require){ var b = require('./b'); b.sayHello(); }); require(['./c'], function(c){ c.sayHello(); }); ~~~ 打包后的代碼: * bundle.js -> main.js + a.js * 1.bundle.js -> b.js * 2.bundle.js -> c.js > [第三章 webpack進階-分片](https://webpack.toobug.net/zh-cn/chapter3/chunks.html ## 各種Loader配置:module 參數 webpack的核心實際上也只能針對 js 進行打包,那 webpack 一直號稱能夠打包任何資源是怎么一回事呢? 原來,webpack擁有一個類似于插件的機制,名為Loader,通過 Loader,webpack 能夠針對每一種特定的資源做出相應的處理。Loader 的種類相當多,有些比較基礎的是官方自己開發,而其它則是由 webpack 社區開源貢獻出來的,這里是 Loader 的List:[list of loaders](https://webpack.docschina.org/loaders/)。 而 module 正是配置什么資源使用哪個 Loader的參數(因為就算是同一種資源,也可能有不同的 Loader 可以使用,當然不同 Loader 處理的手段不一樣,最后結果也自然就不一樣了)。 ### `module.rules` 配置 loaders參數又有幾個子參數,先給出一個官方示例: ``` module: { rules: [ { ???// "test" is commonly used to match the file extension ???test:/\.jsx$/, ? ?// "include" is commonly used to match the directories ???include: [ ?????path.resolve(__dirname,"app/src"), ?????path.resolve(__dirname,"app/test") ???], ? ? // "exclude" should be used to exclude exceptions ? ? // try to prefer "include" when possible ? ? // the "loader" ? ? loader:"babel-loader" } ] } ``` 下面一一對這些子參數進行說明: 1. test:用來指示當前配置項針對哪些資源,該值應是一個條件值(condition)。 2. exclude:用來剔除掉需要忽略的資源,該值應是一個條件值(condition)。 3. include:用來表示本 loader 配置僅針對哪些目錄/文件,該值應是一個條件值(condition)。這個參數跟test參數的效果是一樣的(官方文檔也是這么寫的),我也不明白為嘛有倆同樣規則的參數,不過我們姑且可以自己來劃分這兩者的用途:test 參數用來指示文件名(包括文件后綴),而 include 參數則用來指示目錄;注意同時使用這兩者的時候,實際上是 and 的關系。 4. loader/use:`ule.loader`是`Rule.use: [ { loader } ]`的簡寫。詳細請查看[`Rule.use`](https://webpack.docschina.org/configuration/module/#rule-use)和[`UseEntry.loader`](https://webpack.docschina.org/configuration/module/#useentry)。 需要注意的是,loader 是可以接受參數的,方式類似于 URL 參數,形如`css?minimize&-autoprefixer`,具體每個loader 接受什么參數請參考 loader 本身的文檔(一般也就只能在 github 里看了)。 ## 添加額外功能:plugins參數 這 plugins 參數相當于一個插槽位(類型是數組),你可以先按某個 plugin 要求的方式初始化好了以后,把初始化后的實例丟到這里來。 ## 圖片打包細則 [webpack4 配置 (3)- 打包 css/js/ 圖片等資源](https://juejin.im/post/5cb3fa77e51d456e8c1d3c21) [超詳細使用 webpack4.x 搭建標準前端項目](https://zhuanlan.zhihu.com/p/76689742) ## 集成 jQuery 在本項目中比較特殊,因為對于第三方類庫統一采用了 dll 單獨打包方式,但由于 jQuery 不支持 CDM,所以打包采用 extenal 的形式打包的。 1. 直接引入 我們最常用的引入方式,就是用 AMD 或者 ES6 模塊導入的形式在具體的業務模塊中直接引入: ``` // header.js import $ from 'jquery'; // 或者 const $ = require('jquery'); $('h1').hide(); ``` 如果 webpack 配置文件沒有做其他相關設置,那么在這種情況下,jQuery 源碼會和業務代碼最終會打包到一個文件中。 倘若多個業務模塊都引用了 jQuery,則在打包時,webpack 很機智,不會對 jQuery 源碼進行多次打包。 即**最終打包的文件,只包含一份 jQuery 源碼**。 但在業務代碼中需要反復使用`import $ from 'jquery'`來引入 jQuery 2. Webpack 的 ProvidePlugin 插件: ``` // jQuery引用插件 var jQueryProvidePlugin = new webpack.ProvidePlugin({ ??? $: 'jQuery', ??? jQuery: 'jQuery', ??? 'window.jQuery':'jQuery', ??? 'window.$':'jQuery' }); ``` 然后在我們任意源碼中: ~~~ // in a module $('#item'); // <= 起作用 jQuery('#item'); // <= 起作用 // $ 自動被設置為 "jquery" 輸出的內容 ~~~ 3. expose-loader 先把 jQuery對象聲明成為全局變量`jQuery`,再通過管道進一步又聲明成為全局變量`$`。 ~~~ require("expose-loader?$!jquery"); // loader: 'expose?$!expose?jQuery' ~~~ 或者,你可以通過配置文件來設置: ~~~ // webpack.config.js module: { rules: [{ test: require.resolve('jquery'), use: [{ loader: 'expose-loader', options: 'jQuery' },{ loader: 'expose-loader', options: '$' }] }] } ~~~ [`require.resolve`](https://nodejs.org/api/modules.html#modules_require_resolve_request_options) 調用是一個 Node.js 函數 (與 webpack 處理流程中的`require.resolve`無關)。`require.resolve`用來獲取模塊的絕對路徑。 4. `externals` 防止被打包 針對第三方庫(如 jQuery),我們一般用相對路徑或者**類似 CDN 這種**絕對路徑的形式,以`<script>`標簽在頁面里直接引入。這里我們拿 CDN 上的 jQuery 做演示: ~~~ <!-- index.html --> ... <script src="https://code.jquery.com/jquery-3.1.0.js"></script> ~~~ 最后,無需在業務代碼中引入第三方庫,就能直接使用 jQuery 的 API: ~~~ // header.js $('h1').hide(); ~~~ > [webpack externals 深入理解](https://segmentfault.com/a/1190000012113011) > [webpack 分離第三方庫及公用文件](https://yi-jy.com/2018/06/09/webpack-split-chunks/) # 開發技巧 > [【Hybrid 開發高級系列】WebPack 模塊化專題](https://www.jianshu.com/p/c915685b5c88) ## 多入口配置 多入口的項目 最好是自動獲取目錄下的入口文件: ``` ... const setMPA = () => { const entry = {}; const htmlWebpackPlugins = []; const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js')); Object.keys(entryFiles) .map((index) => { const entryFile = entryFiles[index]; // '/Users/cpselvis/my-project/src/index/index.js' const match = entryFile.match(/src\/(.*)\/index\.js/); const pageName = match && match[1]; entry[pageName] = entryFile; htmlWebpackPlugins.push( new HtmlWebpackPlugin({ template: path.join(__dirname, `src/${pageName}/index.html`), filename: `${pageName}.html`, chunks: [pageName], inject: true, minify: { html5: true, collapseWhitespace: true, preserveLineBreaks: false, minifyCSS: true, minifyJS: true, removeComments: false } }) ); }); return { entry, htmlWebpackPlugins } } const { entry, htmlWebpackPlugins } = setMPA(); module.exports = { ... ``` 其實本質就是如下: ``` ... entry:{ 'index':'./src/index/index.js', // 頁面一的 js 'one':'./src/one/index.js', // 頁面二的 js }, // 輸入路徑 output: { path: path.join(__dirname,'../dist'), // 輸出的路徑 filename: "[name].build.js", // 分別輸出不同的 js,【name】是跟上面的 entry 對應 }, plugins:[ new htmlwebpackplugin({ filename: 'index.html', template: 'src/index/index.html', chunks: ['index'], // 選項的作用主要是針對多入口(entry)文件。當你有多個入口文件的時候,對應就會生成多個編譯后的 js 文件。 // 那么 chunks 選項就可以決定是否都使用這些生成的 js 文件。 // chunks 默認會在生成的 html 文件中引用所有的 js 文件,當然你也可以指定引入哪些特定的文件。 inject: true, hash: true }), new htmlwebpackplugin({ filename: 'one.html', template: 'src/one/index.html', chunks: ['one'], inject: true, hash: true }), ], ... ``` > [《玩轉 webpack》極客時間課程源碼和課件](https://github.com/cpselvis/geektime-webpack-course) # 命令構建輸出 示例: ~~~ Hash: aafe36ba210b0fbb7073 Version: webpack 4.1.1 Time: 338ms Built at: 3/16/2018 3:40:14 PM Asset Size Chunks Chunk Names main.js 679 bytes 0 [emitted] main index.html 181 bytes [emitted] Entrypoint main = main.js [0] ./src/index.js + 1 modules 219 bytes {0} [built] | ./src/index.js 77 bytes [built] | ./src/component.js 142 bytes [built] Child html-webpack-plugin for "index.html": 1 asset Entrypoint undefined = index.html [0] (webpack)/buildin/module.js 519 bytes {0} [built] [1] (webpack)/buildin/global.js 509 bytes {0} [built] + 2 hidden modules ~~~ 輸出告訴了我們許多: * `Hash: aafe36ba210b0fbb7073`\- 構建生成的唯一 hash 標志。 你可以`[hash]`來驗證靜態資源(assets)是否有效。hash 的使用將在[*在文件名中添加 hash*](https://lvzhenbang.github.io/webpack-book/dist/zh/optimizing/04_adding_hashes_to_filenames.html)這章詳解。 * `Version: webpack 4.1.1`\- Webpack 的版本。 * `Time: 338ms`\- 構建完成所花費的時間。 * `main.js 679 bytes 0 [emitted] main`\- 生成的靜態資源名稱、大小、相關聯模塊的 ID、狀態、模塊名字。 * `index.html 181 bytes [emitted]`\- 構建過程中生成的另一個靜態資源。 * `[0] ./src/index.js + 1 modules 219 bytes {0} [built]`\- 入口靜態資源的 ID、名字、大小、入口 ID、生成方式。 * `Child html-webpack-plugin for "index.html":`\- 輸出使用的插件。 # 整體配置結構 ~~~ const webpack= require('webpack'); const path = require('path'); const TerserPlugin = require('terser-webpack-plugin'); // 混淆壓縮 js module.exports = { mode: 'production', // (默認值),https://webpack.docschina.org/concepts/mode // entry 表示 入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。 // 類型可以是 string | object | array entry: './app/entry', // 只有1個入口,入口只有1個文件 entry: ['./app/entry1', './app/entry2'], // 只有1個入口,入口有2個文件 entry: { // 有2個入口 a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2'] }, // 如何輸出結果:在 Webpack 經過一系列處理后,如何輸出最終想要的代碼。 output: { // 輸出文件存放的目錄,必須是 string 類型的絕對路徑。 path: path.resolve(__dirname, 'dist'), // 輸出文件的名稱 filename: 'bundle.js', // 完整的名稱 filename: '[name].js', // 當配置了多個 entry 時,通過名稱模版為不同的 entry 生成不同的文件名稱 filename: '[chunkhash].js', // 根據文件內容 hash 值生成文件名稱,用于瀏覽器長時間緩存文件 // 發布到線上的所有資源的 URL 前綴,string 類型 publicPath: '/assets/', // 放到指定目錄下 publicPath: '', // 放到根目錄下 publicPath: 'https://cdn.example.com/', // 放到 CDN 上去 // 導出庫的名稱,string 類型 // 不填它時,默認輸出格式是匿名的立即執行函數 library: 'MyLibrary', // 導出庫的類型,枚舉類型,默認是 var // 可以是 umd | umd2 | commonjs2 | commonjs | amd | this | var | assign | window | global | jsonp , libraryTarget: 'umd', // 是否包含有用的文件路徑信息到生成的代碼里去,boolean 類型 pathinfo: true, // 附加 Chunk 的文件名稱 chunkFilename: '[id].js', chunkFilename: '[chunkhash].js', // JSONP 異步加載資源時的回調函數名稱,需要和服務端搭配使用 jsonpFunction: 'myWebpackJsonp', // 生成的 Source Map 文件名稱 sourceMapFilename: '[file].map', // 瀏覽器開發者工具里顯示的源碼模塊名稱 devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // 異步加載跨域的資源時使用的方式 crossOriginLoading: 'use-credentials', crossOriginLoading: 'anonymous', crossOriginLoading: false, }, // 配置模塊相關 module: { rules: [ // 配置 Loader { test: /\.jsx?$/, // 正則匹配命中要使用 Loader 的文件 exclude: [ // 不解析這里面的文件 path.resolve(__dirname, 'app/demo-files') ], include: [ // 只解析這目錄下的文件,兩者寫其一即可 path.resolve(__dirname, 'app') ], use: [ // 使用那些 Loader,有先后次序,從后往前執行 'style-loader', // 直接使用 Loader 的名稱 { loader: 'css-loader', options: { // 給 css-loader 傳一些參數 } } ] }, ], // 防止解析那些任何與給定正則表達式相匹配的文件,忽略的文件中不應該含有任何導入機制。忽略大型的`library`可以提高構建性能。 // 使用正則表達式:noParse: /jquery|lodash/ // 使用函數,從 Webpack 3.0.0 開始支持 noParse: (content)=> { // content 代表一個模塊的文件路徑 // 返回 true or false return /jquery|lodash/.test(content); } noParse: /jquery|lodash/ }, // 配置插件 plugins: [ new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // 使用`IgnorePlugin`在打包時忽略本地化內容 ], // 配置尋找模塊的規則 resolve: { modules: [ // 尋找模塊的根目錄,array 類型,默認以 node_modules 為根目錄 'node_modules', path.resolve(__dirname, 'app') ], extensions: ['.js', '.json', '.jsx', '.css'], // 模塊的后綴名 alias: { // 模塊別名配置,用于映射模塊 // 把 'module' 映射 'new-module',同樣的 'module/path/file' 也會被映射成 'new-module/path/file' 'module': 'new-module', // 使用結尾符號 $ 后,把 'only-module' 映射成 'new-module', // 但是不像上面的,'module/path/file' 不會被映射成 'new-module/path/file' 'only-module$': 'new-module', }, alias: [ // alias 還支持使用數組來更詳細的配置 { name: 'module', // 老的模塊 alias: 'new-module', // 新的模塊 // 是否是只映射模塊,如果是 true 只有 'module' 會被映射,如果是 false 'module/inner/path' 也會被映射 onlyModule: true, } ], symlinks: true, // 是否跟隨文件軟鏈接去搜尋模塊的路徑 descriptionFiles: ['package.json'], // 模塊的描述文件 mainFields: ['main'], // 模塊的描述文件里的描述入口的文件的字段名稱 enforceExtension: false, // 是否強制導入語句必須要寫明文件后綴 }, // 輸出文件性能檢查配置 performance: { hints: 'warning', // 有性能問題時輸出警告 hints: 'error', // 有性能問題時輸出錯誤 hints: false, // 關閉性能檢查 maxAssetSize: 200000, // 最大文件大小 (單位 bytes) maxEntrypointSize: 400000, // 最大入口文件大小 (單位 bytes) assetFilter: function(assetFilename) { // 過濾要檢查的文件 return assetFilename.endsWith('.css') || assetFilename.endsWith('.js'); } }, devtool: 'source-map', // 配置 source-map 類型 context: __dirname, // Webpack 使用的根目錄,string 類型必須是絕對路徑 // 配置輸出代碼的運行環境 target: 'web', // 瀏覽器,默認 target: 'webworker', // WebWorker target: 'node', // Node.js,使用 `require` 語句加載 Chunk 代碼 target: 'async-node', // Node.js,異步加載 Chunk 代碼 target: 'node-webkit', // nw.js target: 'electron-main', // electron-主線程 target: 'electron-renderer', // electron-渲染線程 externals: { // 使用來自 JavaScript 運行環境提供的全局變量 jquery: 'jQuery' }, stats: { // 控制臺輸出日志控制 assets: true, colors: true, errors: true, errorDetails: true, hash: true, }, devServer: { // DevServer 相關的配置 proxy: { // 代理到后端服務接口 '/api': 'http://localhost:3000' }, contentBase: path.join(__dirname, 'public'), // 配置 DevServer HTTP 服務器的文件根目錄 compress: true, // 是否開啟 gzip 壓縮 historyApiFallback: true, // 是否開發 HTML5 History API 網頁 hot: true, // 是否開啟模塊熱替換功能 hotOnly: true // 如果模塊熱替換功能不生效,則不刷新網頁 https: false, // 是否開啟 HTTPS 模式 }, profile: true, // 是否捕捉 Webpack 構建的性能信息,用于分析什么原因導致構建性能不佳 cache: false, // 是否啟用緩存提升構建速度 watch: true, // 是否開始 watchOptions: { // 監聽模式選項 // 不監聽的文件或文件夾,支持正則匹配。默認為空 ignored: /node_modules/, // 監聽到變化發生后會等300ms再去執行動作,防止文件更新太快導致重新編譯頻率太高 // 默認為300ms aggregateTimeout: 300, // 判斷文件是否發生變化是不停的去詢問系統指定文件有沒有變化,默認每秒問 1000 次 poll: 1000 }, //===優化 optimization=== optimization: { minimizer: [ new TerserPlugin({ cache: true, parallel: true, sourceMap: true, terserOptions: { // https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions } }) ] }, // 默認配置 splitChunks: { chunks: 'async', // all 全部(推薦), async 分割異步塊, initial minSize: 30000, // 抽取出來的文件在壓縮前的最小大小 maxSize: 0, // 抽取出來的文件在壓縮前的最大大小, 默認為 0,表示不限制最大大小 minChunks: 1, // 最小公用模塊次數 maxAsyncRequests: 5, // 按需加載時并行請求的最大數量 maxInitialRequests: 3, // 入口點的最大并行請求數 automaticNameDelimiter: '~', // 文件名稱分隔符號 // 文件名,值可以是 boolean | function (module, chunks, cacheGroupKey) | string name: true, // 緩存策略,默認設置了分割 node_modules 和公用模塊 // 會繼承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用于配置緩存組 cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 // 優先級 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true // 是否復用存在的 chunk } } } } ~~~ > [時下最流行前端構建工具Webpack 入門總結](https://mp.weixin.qq.com/s/vdOnXCUGWv6oEEIaKOXFuQ) # Webpack tricks [使用Webpack的技巧和竅門](https://github.com/rstacruz/webpack-tricks) # 參考 [如何使用Webpack創建JavaScript library](https://github.com/iuap-design/blog/issues/323) https://x-team.com/blog/rollup-webpack-parcel-comparison/ [Webpack的由來](https://survivejs.com/webpack/foreword/) http://webpack.wuhaolin.cn/
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看