# Webpack Basic ###### tags: `Tools` `JavaScript` ## 1. Webpack入門 ### 簡介 * webpack是一個前端資源建構工具。 * 一个靜態模組打包器(modulebundler)。 * 在webpack中,前端的所有資源(js/json/css/img/less/...)都會作為模組處理。 * 根據依賴關係生成的樹狀結構將相關依賴導入,形成塊(chunk),再根據塊來打包轉換生成對應的靜態資源(bundle)給瀏覽器解析。 ### 5個核心概念 #### Entry 入口(Entry)指示webpack以哪個檔案為入口作為起點開始打包,分析構建内部依賴圖。 #### Output 輸出(Output)指示webpack打包後的資源bundles輸出到哪裡去,以及如何命名。 #### Loader Loader讓webpack能夠去處理那些非JavaScript文件(webpack自身只理解JavaScript) #### Plugins 插件(Plugins)可以用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓缩,一直到重新定義環境中的變數等。 #### Mode 模式(Mode)指定webpack使用對應模式的設定。 | 選項 | 描述 | 特點 | | -------- | -------- | -------- | | development | 會將DefinePlugin中process.env.NODE_ENV的值設定為development。啟用NamedChunksPlugin和NamedModulesPlugin。 | 能讓程式碼本機調適運行的環境 | | production | 會將DefinePlugin中process.env.NODE_ENV的值設定為production。啟用FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin,OccurrenceOrderPlugin,SideEffectsFlagPlugin和TerserPlugin。 | 能讓程式碼優化上線運行的環境 | ## 2.webpack的初體驗 ### 初始化設定 * 初始化package.json:npm init * 下載並安裝webpack: * npm install webpack webpack-cli-D ### 編譯打包應用 必須先透過npm init指令來初始化設定 ![](https://i.imgur.com/95kne7C.png) ## 3.webpack開發環境的基本設定 ### 打包樣式資源 1. 建立檔案webpack.config.js ```javascript= /* webpack.config.js是webpack的設定檔案 作用:指示webpack幹那些活(當你運行webpack指令時,會加載裡面的設定) 所有建構工具都是基於nodejs平台運行的~模組化預設採用commonjs */ //用來拼接絕對路徑的方法 const {resolve} = require('path') module.exports = { //webpack設定 //入口起點 entry: './src/index.js', //輸出 output:{ //輸出文件名 filename: 'built.js', //輸出路徑 //__dirname是nodejs的變數,代表當前文件的目錄絕對路徑 path: resolve(__dirname, 'build') }, //loader的設定 module:{ rules:[ //詳細loader設定 //不同文件必須配置不同loader處理 { //匹配那些檔案 test: /\.css$/, //使用哪些loader進行處理 use:[ //use陣列中loader執行順序:從右到左,從上到下依次執行 //創建style標籤,將js中的樣式資源插入進行,添加到head中生效 'style-loader', //將css檔案變成commonjs模組加載js中,裡面內容是樣式字串 'css-loader' ] }, { test:/\.less$/, use:[ 'style-loader', 'css-loader', 'less-loader' ] } ] }, //plugins的設定 // Plugins:[ // //詳細plugins的設定 // ], //模式 mode:'development' } ``` 2. 安裝各種loader包: * npm i css-loader style-loader less-loader less -D 3. 指令:webpack ### 打包HTML資源 1. 安裝plugin包: npm install html-webpack-plugin -D 2. 建立webpack設定檔案![](https://i.imgur.com/kTEWMcV.png) ### 打包圖片資源 ![](https://i.imgur.com/yxHjE8b.png) ```javascript= const {resolve} = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: './src/index.js', output:{ filename: 'built.js', path : resolve(__dirname,'build') }, module:{ rules:[ { test: /\.less$/, //要使用多個loader處理用use use:[ 'style-loader', 'css-loader', 'less-loader' ] }, { //問題:預設處理不了html中的img圖片 //處理圖片資源 test: /\.(jpg|png|gif)$/, //使用一個loader //下載 url-loader file-loader loader: 'url-loader', options:{ //圖片大小小於8kb,就會被base64處理 //優點:減少請求數量(減輕伺服器壓力) //缺點:圖片大小會更大(檔案請求速度更慢) limit: 8 * 1024, //問題:因為url-loader預設使用es6模組化解析,而html-loader導入圖片是commonjs //解析時會出問題: [object Module] //解決:關閉url-loader的es6模組化,使用commonjs解析 esModule: false, //給圖片進行重新命名 //[hash:10]取圖片的hash的前10位 //[ext]取檔案原來的副檔名 name: '[hash:10].[ext]' } }, { test: /\.html$/, //處理html檔案的img圖片(負責導入img,從而能被url-loader進行處理) loader: 'html-loader' } ] }, plugins:[ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development' } ``` ### 打包其他資源 ![](https://i.imgur.com/fUzmRlw.png) ```javascript= const HtmlWebpackPlugin = require('html-webpack-plugin') const{resolve} = require('path') module.exports = { entry: './src/index.js', output:{ filename:'built.js', path:resolve(__dirname,'build') }, module:{ rules:[ { test:/\.css$/, use:['style-loader','css-loader'] }, //打包其他資源(除了html/js/css資源以外的資源) { //排除 exclude:/\.(css|js|html)$/, loader:'file-loader' } ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], mode:'development' } ``` ### devServer ```javascript= const HtmlWebpackPlugin = require('html-webpack-plugin') const{resolve} = require('path') module.exports = { entry: './src/index.js', output:{ filename:'built.js', path:resolve(__dirname,'build') }, module:{ rules:[ { test:/\.css$/, use:['style-loader','css-loader'] }, //打包其他資源(除了html/js/css資源以外的資源) { //排除 exclude:/\.(css|js|html)$/, loader:'file-loader' } ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], mode:'development', //開發伺服器devServer:用來自動化(自動編譯,自動打開瀏覽器,自動重新整理) //特點:只會在記憶體中編譯打包,不會有任何輸出 //啟動devServer指令為:npx webopack-dev-server devServer:{ //項目構建後路徑 contentBase:resolve(__dirname, 'build'), //啟動gzip壓縮 compress:true, //port number port:3000, //自動打開瀏覽器 open:true } } ``` ## 4.webpack生產環境的基本設定 ### 提取css成單獨檔案 插件安裝:npm install mini-css-extract-plugin ![](https://i.imgur.com/fDIiBCP.png) ```javascript= const { resolve } = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname,'build') }, module:{ rules:[ { test: /\.css$/, use:[ //'style-loader', //這個loader取代style-loader,作用:提取js中的css成單獨檔案 MiniCssExtractPlugin.loader, //將css檔案整合到js檔案中 'css-loader' ] } ] }, plugins:[ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ //對輸出的檔案改名 filename: 'css/built.css' }) ], mode: 'development' } ``` ### css兼容性處理 安裝loader:npm install postcss-loader postcss-preset-env ```javascript= const { resolve } = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require('mini-css-extract-plugin') //設定nodejs環境變數 //process.env.NODE_ENV = 'development' module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname,'build') }, module:{ rules:[ { test: /\.css$/, use:[ MiniCssExtractPlugin.loader, 'css-loader', /* css兼容性處理:postcss --> postcss-loader postcss-preset-env 幫postcss找到package.json中browerslist裡面的設定,透過設定加載指定的css兼容性樣式 "browserslist":{ //開發環境 --> 設定node環境變數:process.env.NODE_ENV = development "development":[ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ], //生產環境:預設是看生產環境 "production":[ ">0.2%", "not dead", "not op_mini all" ] } */ //使用loader的預設設定 //'postcss-loader', { loader: 'postcss-loader', options:{ ident:'postcss', plugins:() => [ //postcss的插件 require('postcss-preset-env')() ] } } ] } ] }, plugins:[ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ //對輸出的檔案改名 filename: 'css/built.css' }) ], mode: 'development' } ``` ### 壓縮css檔案 安裝插件:npm install optimize-css-assets-webpack-plugin ```javascript= const { resolve } = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require('mini-css-extract-plugin') const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') //設定nodejs環境變數 //process.env.NODE_ENV = 'development' // optimize-css-assets-webpack-plugin module.exports = { entry: './src/js/index.js', output: { filename: 'js/built.js', path: resolve(__dirname,'build') }, module:{ rules:[ { test: /\.css$/, use:[ MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options:{ ident:'postcss', plugins:() => [ //postcss的插件 require('postcss-preset-env')() ] } } ] } ] }, plugins:[ new HtmlWebpackPlugin({ template: './src/index.html' }), new MiniCssExtractPlugin({ //對輸出的檔案改名 filename: 'css/built.css' }), //壓縮css new OptimizeCssAssetsWebpackPlugin() ], mode: 'development' } ``` ### js語法檢查eslint 下載安裝包:npm install eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import ```javascript= const HtmlWebpackPlugin = require("html-webpack-plugin"); const { resolve } = require("path"); module.exports = { entry: './src/js/index.js', output:{ filename:'js/built.js', path: resolve(__dirname,'build') }, module:{ rules:[ /* 語法檢查:eslint-loader eslint 注意:只檢查自己寫的原程式碼,第三方的lib是不用檢查的 設定檢查規則: package.json中eslintConfig中設定~ "eslintConfig": { "extends": "airbnb-base" } airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint */ { test:/\.js$/, exclude:/node_modules/, loader:'eslint-loader', options:{ //自動修復eslint的錯誤 fix: true } } ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], mode: 'development' } ``` ### js兼容性處理 下載安裝包:npm install babel-loader @babel/core @babel/preset-env @babel/polyfill core-js ```javascript= const HtmlWebpackPlugin = require("html-webpack-plugin"); const { resolve } = require("path"); module.exports = { entry: './src/js/index.js', output:{ filename:'js/built.js', path: resolve(__dirname,'build') }, module:{ rules:[ /* js兼容性處理:babel-loader @babel/preset-env 1.基本js兼容性處理 --> @babel/preset-env 問題:只能轉換基本語法,如promise高級語法不能轉換 2.全部js兼容性處理 --> @babel/polyfill 問題:我只要解決部分兼容性問題,但是將所有兼容性程式碼全都導入,體積太大了~ 3.需要做兼容性處理的就做:按需加載 --> corejs */ { test:/\.js$/, exclude: /node_modules/, loader:'babel-loader', options:{ //預設:指定babel做怎麼樣的兼容性處理 presets: [ [ '@babel/preset-env', { //按需加載 useBuiltIns:'usage', //指定core-js版本 corejs:{ version: 3 }, //指定兼容性做到哪個版本瀏覽器 targets:{ chrome: '60', firefox: '60', ie: '9', safari: '10', edge: '17' } } ] ] } } ] }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], mode: 'development' } ``` ### 壓縮html與js js: ```javascript= const HtmlWebpackPlugin = require("html-webpack-plugin"); const { resolve } = require("path"); module.exports = { entry: './src/js/index.js', output:{ filename:'js/built.js', path: resolve(__dirname,'build') }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html' }) ], //生產環境下會自動壓縮js程式碼 mode: 'production' } ``` html: ```htmlembedded= const HtmlWebpackPlugin = require("html-webpack-plugin"); const { resolve } = require("path"); module.exports = { entry: './src/js/index.js', output:{ filename:'js/built.js', path: resolve(__dirname,'build') }, plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html', //壓縮html程式碼 minify:{ //移除空格 collapseWhitespace: true, //移除註釋 removeComments: true } }) ], mode: 'production' } ``` ## 5.webpack優化設定 * 開發環境性能優化 * 優化打包建構速度 * 優化程式碼調適 * 生產環境性能優化 * 優化打包建構速度 * 優化程式碼執行的性能