webpack4.0 把本身總結'吐'的一篇文章

上大學的時候老師講一門語言,上來的第一節課就是配置各類環境,而一般看到那些腦殼都是一種快要炸的狀態🤯。隨着後來對Linux的學習以後發現,並無那麼頭疼配置的東西(對於命令這麼複雜的東西均可以接受,那麼配置是否是也不顯得那麼枯燥了😂)。css

本章是結合本身項目中的應該以及查看了webpack官方文檔以後總結的一篇配置。目的也是鍛鍊本身在配置方面的興趣(可能大家不懂噁心配置的那種感受😩,只能慢慢克服)若有錯誤,還請各位大佬指出🙏,小女子在此謝過🤪。html

話很少說,看正文👇前端

1、webpack的認識

webpack可以把咱們項目中引入的一個或者多個css或者JS資源文件,最終安裝指定的依賴可以打包壓縮成一個css或者一個JS,以此來實現咱們的性能優化。以這種自動化的方法來完成項目的部署和構建,告別了手工。webpack是基於node.js開發的vue

在項目中的應用

  • 代碼轉換:TypeScript編譯成JavaScript、LESS/SCSS編譯成CSS、ES6/7編譯爲ES五、虛擬DOM編譯爲真實的DOM等等…
  • 文件優化:壓縮JS、CSS、HTML代碼,壓縮合並圖片,圖片BASE64等
  • 代碼分割:提取多個頁面的公共代碼、提取首屏不須要執行部分的代碼等
  • 模塊合併:在採用模塊化的項目裏會有不少個模塊和文件,須要構建功能把模塊分類合併成一個文件
  • 自動刷新:監聽本地源代碼的變化,自動從新構建、刷新瀏覽器
  • 代碼校驗:Eslint代碼規範校驗和檢測、單元測試等
  • 自動發佈:自動構建出線上發佈代碼並傳輸給發佈系統
  • ……

webpack同類型工具

  • grunt
  • gulp
  • fis
  • webpack(Browserify / Parcel [ˈpɑːsl])
  • snowpack

webpack中文網學習

webpack中文網地址node

2、前端模塊化開發進化史

JavaScript自己是弱化命名空間概念的,只有全局做用域和函數的私有做用域(ES6中新增塊做用域),而模塊化開發,從某種意義上來講,是強化了命名空間的概念!react

  • 有利於代碼分離、解耦以及複用
  • 團隊並行開發
  • 避免命名衝突
  • 相互引用,按需加載
  • ……

單利設計模式

let xxxModule=(function(){
 function fn(){  //...  }  return {  init(){  //...   }  } })();  xxxModule.init(); 複製代碼

AMD (Asynchronous Module Definition 異步模塊定義)

若是須要使用外面的模塊,須要先引入該模塊,可是這種方式在如今的項目中已經不經常使用jquery

文件目錄:webpack

|- lib
   |- moduleA.js
   |- moduleB.js
|- main.js
git

//main.js
//全局配置 require.config({  baseUrl: 'js/lib', }); require(['moduleB', 'moduleA'], function (moduleB, moduleA) {  console.log(moduleB.average(10, 20, 30, 40, 50)); }); 複製代碼
//moduleA.js
define(function () {  return {  sum(...args) {  return args.reduce((total, item) => {  return total + item;  });  }  }; }); 複製代碼
define(['moduleA'], function (moudleA) {
 return {  average(...args) {  args.sort((a, b) => a - b);  args.pop();  args.shift();  return moudleA.sum(...args) / args.length;  }  }; }); 複製代碼

CMD (Common Module Definition 通用模塊定義)

define(function(require, exports, module) {
 // 經過 require 引入依賴  let $ = require('jquery');  let spinning = require('./spinning');   // 經過 module.exports 提供接口  module.exports = {  init(){}  }; }); 複製代碼

CommonJS(通常應用於服務器開發,例如:Node.js)

  • 導出: module.exports
  • 導入: require
//CommonJS規範的使用
let A = require('./A'); // 第一次REQUIRE A模塊,會把A模塊中的代碼執行, //建立的變量A就是把模塊中module.exports導出的結果拷貝一份給變量 A.sum(x, y);   A = require('./A'); // 第二次REQUIRE A模塊,內部默認會看一下以前有沒有導入過,若是導入過不會再把A代碼從新執行,而是直接獲取上一次拷貝的信息 複製代碼

ES6 Module (ESM : JS官方標準模塊定義方式)

//ES6模塊導入導出的使用
/*  * ES6Module是JS新增的模塊導入導出規範(不一樣於AMD 和 CMD【CommonJS】,它是靜態編譯的)  * 動態編譯:代碼執行到具體位置的時候纔會進行模塊的導入導出  * (在第十行導入那麼就在第十行才進行導入)  * 靜態編譯:代碼尚未執行,就按照依賴的關係吧模塊導入導出和編譯好了  * 模塊的導入都要放在執行的最前面  * 瀏覽器不能直接識別,須要先進行編譯才能夠(webpack能夠完成這個編譯) */ //導出 export function sum(x, y) {  return x + y; }  export let n = 10; //導入 2種方式 import {sum,n} form './A.js'; import * as A form './A.js' 複製代碼

3、安裝webpack

目前@vue/cli和create-react-app基本上採用的是webpack 4.0以上版本,因此以第四代版本爲主;第四代版本須要咱們安裝webpack和webpack-cli(可執行命令)github

// 爲防止全局安裝webpack致使版本衝突,項目中以本地安裝爲主 
$ npm init -y //生成package.json文件 $ npm install webpack webpack-cli --save-dev //安裝開發依賴 // OR $ yarn add webpack webpack-cli -D //若是安裝過yarn的能夠時候這個,速度會快一些 複製代碼

掃盲

  • 生產依賴:服務器部署的環境 --save
  • 開發依賴:本地開發的環境 --save-dev (在本地使用less進行css的編寫,可是在項目上傳的時候不須要把less上傳。由於已經把它生成了.css的文件,若是把less上傳上去,每次都會編譯,影響性能,所以less就屬於一個在開發依賴須要的模塊)

4、零基礎配置使用webpack

運行命令(如下任何一條均可以)

  • $npx webpack
  • 在package.json文件的script中配置命令,而後按照下面的命令執行
    • npm run serve
    • yarn serve
/*  * 默認會打包SRC目錄中的JS文件(入口默認index.js)  * 打包完成的目錄默認是DIST/MAIN.JS  * webpack默認支持CommonJS和ES6 Module的模塊規範,依此進行依賴打包  */ $ npx webpack 複製代碼
運行webpack配置
運行webpack配置

5、自定義基礎配置--配置文件名

配置須要寫的文件名

若是咱們須要去自定義配置一些文件,首先須要知道這些配置須要寫在哪裏。這裏無論寫在什麼配置文件裏,區別就是執行webpack的命令不同。

webpack默認支持的配置文件名

  • webpack.config.js(這種經常使用)
  • webpackfile.js 上面兩種是 webpack默認支持的配置文件名,那麼在執行的時候使用 npx webpack或者在 package.json文件中本身配置可執行的命令(上面剛提到的)。

自定義配置文件名

在項目中有時候須要把咱們的配置文件名稱分爲開發配置和生產配置,若是是這個配置文件名那麼在執行webpack的時候應該使用什麼命令。

好比如今我把本身的配置項寫在webpack.config.dev.js裏。

第一種方式:那麼須要在上面執行的命令中加入指定的入口npx webpack --config webpack.config.dev.js。格式就是:npx webpack --config 配置文件名

第二種方式:在package.json文件裏配置這個命令。好比我想在執行npm run serve的時候是把只配置的東西執行。就是以下的配置方式:

"scripts": {
 "serve": "webpack --config webpack.config.dev.js" }, 複製代碼

以上就是咱們須要在寫本身配置的時候,對於配置文件名的處理。

6、配置項目中文件的出口入口

const path = require('path');
 module.exports = {  // 設置編譯的模式 development/production(默認)  mode: 'production',  // 設置編譯的入口文件(項目中通常開發的代碼都要放置到SRC下)  entry: './src/main.js',  // 設置編譯的出口文件  output: {  // 編譯後的文件名 [hash]編譯的時候會隨機在名字中生成惟一的哈希值,以此保證每一次編譯出來的文件是不同的  filename: 'bundle.[hash].min.js',  // 輸出的目錄(須要是絕對路徑,使用path完成)  path: path.resolve(__dirname, 'build')  } }; 複製代碼
配置出口入口
配置出口入口

7、webpack經常使用插件

咱們把插件的相關配置都放在plugins中,是一個數組

html-webpack-plugin

  • 想要使用插件,需先安裝插件 $yarn add html-webpack-plugin -D
  • 插件的做用: 每一次代碼更改,從新編譯後,都須要手動的去更改指定HTML頁面中的導入的JS信息,而這個插件幫咱們處理的就是對於HTML的編譯和導入文件的自動處理
目錄結構
目錄結構
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');  module.exports = {  mode: 'production',  entry: './src/main.js',  output: {  filename: 'bundle.js',  path: path.resolve(__dirname, 'dist')  },  // 在WEBPACK中使用插件  plugins: [  // 配置指定的HTML頁面模板(後期在編譯的時候會把編譯好的資源文件自動導入到咱們的頁面模板中)  new HtmlWebpackPlugin({  // 模板的路徑  template: './public/index.html',  // 編譯後生成的文件名  filename: 'index.html',  // 是否把編譯的資源文件導入到頁面中,設置HASH值(清除強緩存,和OUTPUT設置HASH值是同樣的)  hash: true,  // 把模板中的HTML代碼也進行壓縮編譯(配置規則)  // https://github.com/kangax/html-minifier  minify: {  collapseWhitespace: true,  removeComments: true,  removeAttributeQuotes: true,  removeEmptyAttributes: true  }  }),  ] } 複製代碼

clean-webpack-plugin

  • 想要使用插件,需先安裝插件 $yarn add clean-webpack-plugin -D
  • 插件的做用: 每一次打包的時候都把以前打包的內容清空掉,也就是在編譯好的文件夾下只保留最新打包的文件
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); //這裏須要把它解構出來,不然不能使用 const { CleanWebpackPlugin } = require('clean-webpack-plugin');  module.exports = {  mode: 'production',  entry: './src/main.js',  output: {  filename: 'bundle.js',  path: path.resolve(__dirname, 'dist')  },  // 在WEBPACK中使用插件  plugins: [  new HtmlWebpackPlugin({  template: './public/index.html',  filename: 'index.html',  hash: true,  minify: {  collapseWhitespace: true,  removeComments: true,  removeAttributeQuotes: true,  removeEmptyAttributes: true  }  }),  // 每一次打包都把以前打包的清空  new CleanWebpackPlugin()  ] } 複製代碼

8、webpack-dev-server

能夠幫咱們建立一個web服務(不在用vscode的live server了),服務能夠作如下的事情:

  • 自動監聽代碼的改變,若是代碼改變自動編譯
  • 自動幫咱們打開瀏覽器渲染頁面
  • 從新編譯後自動刷新瀏覽器看到最新的效果

【除非配置項更改了,須要本身從新執行,不然直接都基於它完成自動化處理】

  • 使用它的時候,須要執行的命令是 $npx webpack-dev-server,這樣能夠一直監聽
// 配置DEV-SERVER 編譯後的結果放在計算機內存中,並不會向以前的webpack命令同樣,把編譯後的東西放到build下,dev-server僅僅是在開發模式下,隨時編譯而且預覽的,項目要部署的時候,仍是須要基於webpack編譯打包的
 devServer: {  // WEB服務的端口號  port: '3000',  // 開啓GZIP壓縮  compress: true,  // 指定資源訪問的路徑  contentBase: path.resolve(__dirname, "build"),  // 自動打開瀏覽器  open: true,  // 開啓熱更新  hot: true,  // Proxy跨域代理  // proxy: {  // '/': 'http://127.0.0.1:8888'  // }  }, 複製代碼

9、多入口 多出口配置

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const {  CleanWebpackPlugin } = require('clean-webpack-plugin');  // 配置多頁面模板 const htmlPlugins = ['index', 'login'].map(item => {  return new HtmlWebpackPlugin({  template: `./public/${item}.html`,  filename: `${item}.html`,  // chunks: ['jquery', item], // 指定當前頁面的依賴項,先引誰就把誰放在前面  chunks: [item],  minify: {  collapseWhitespace: true,  removeComments: true,  removeAttributeQuotes: true,  removeEmptyAttributes: true  }  }); });  module.exports = {  // 基礎配置  mode: 'production',  // entry: './src/main.js',  // 多入口 KEY:VALUE  entry: {  index: './src/main.js',  login: './src/login.js',  // 若是不想把JQ合併在其它的JS中,想獨立打包出來(多個頁面公共的部分咱們能夠獨立打包出來)  // jquery: 'jquery' //內置模塊不須要放在src目錄下  },  output: {  // [name]多入口中配置的屬性名 index/login  filename: '[name].[hash].min.js',  path: path.resolve(__dirname, 'build')  },  // 配置DEV-SERVER  devServer: {  port: '3000',  compress: true,  open: true,  hot: true  },  plugins: [  // 配置指定的HTML頁面模板  ...htmlPlugins,  // 每一次打包都把以前打包的清空  new CleanWebpackPlugin()  ] }; 複製代碼

10、webpack加載器loader

加載器寫在 module 裏面

處理CSS樣式

  • 安裝須要的模塊 $yarn add css-loader style-loader less less-loader autoprefixer postcss-loader -D
  • 須要配置下面的三個,爲了處理 css的前綴以及兼容的
  • 這種方式下 css是內嵌式的
module.exports = {
 // 配置WEBPACK的加載器LOADER  module: {  // 設置規則和處理方案 默認執行順序:從右到左、從下向上  rules: [{  // 匹配哪些文件基於正則處理(此處是處理CSS/LESS文件)  test: /\.(css|less)$/i,  use: [  "style-loader", // 把處理好的CSS插入到頁面中(內嵌式)  "css-loader", // 處理@import/URL這種語法  "postcss-loader", // 設置CSS前綴(處理兼容 須要搭配autoprefixer一塊兒使用,須要而外再配置一些信息)  "less-loader" // 把LESS編譯爲CSS  ]  }]  } }; 複製代碼

postcss.config.js

module.exports = {
 plugins: [  require('autoprefixer')  ] }; 複製代碼

package.json

// https://github.com/browserslist/browserslist 學習網站
/*  * "> 1%" 兼容99%的瀏覽器 * "last 2 versions" 兼容最近的兩個版本 */ "browserslist": [  "> 1%",  "last 2 versions" ] 複製代碼

抽離CSS到指定的目錄下 mini-css-extract-plugin

它是一個插件,使用插件先下載

  • $ yarn add mini-css-extract-plugin –D

這種執行完css是經過link標籤引入到頁面的

const MiniCssExtractPlugin=require('mini-css-extract-plugin');
module.exports = {  plugins: [  //=>使用插件  new MiniCssExtractPlugin({  //=>設置編譯後的文件名字  filename: 'main.[hash].css'  })  ],  module: {  rules: [{  test: /\.(css|less)$/,  use: [  // "style-loader",  //=>使用插件中的LOADER代替STYLE方式  MiniCssExtractPlugin.loader,  "css-loader",  "postcss-loader",  "less-loader"  ]  }]  } } 複製代碼

優化項壓縮CSS/JS

$yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin terser-webpack-plugin -D

const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin= require('optimize-css-assets-webpack-plugin');  module.exports = {  //=>設置優化項  optimization: {  //=>設置壓縮方式  minimizer: [  //=>壓縮CSS(可是必須指定JS的壓縮方式)  new OptimizeCssAssetsWebpackPlugin(),  //=>壓縮JS  new TerserPlugin()  ]  } }; 複製代碼

11、webpack中圖片的處理

$yarn add file-loader url-loader html-withimg-loader -D

module.exports = {
 module: {  //=>模塊規則:使用加載器(默認從右向左執行)  rules: [{  // 圖片的處理 file-loader就是編譯圖片的加載器  test: /\.(png|jpe?g|gif|ico|bmp|svg|eot|ttf|woff|woff2)$/i,  use: [{  // url-loader在編譯的時候,會把符合條件的圖片進行BASE64,對於不符合條件的仍是繼續使用file-loader處理  loader: "url-loader",  options: {  limit: 100 * 1024,  // 在編譯的時候,把圖片都放在統一的IMAGES文件夾下  name: 'images/[name].[hash].[ext]',  esModule: false  }  }],  include: path.resolve(__dirname, 'src'),  exclude: /node_modules/  }, {  // 編譯HTML中的圖片的,把其按照上述圖片的處理機制處理  test: /\.html$/,  use: ['html-withimg-loader']  }]  } } 複製代碼

12、基於babel實現ES6的轉換和ESLint語法檢測

$yarn add babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime -D

$yarn add @babel/runtime @babel/polyfill

$yarn add eslint eslint-loader -D

@babel/polyfill和其它的webpack加載器和插件不同,其它的是編譯時(編譯代碼的時候處理),而polyfill是運行時,是在代碼運行的時候,把一些ES7等特殊的語法進行兼容處理

  1. 須要安裝在生產環境下,由於上線代碼運行時也是須要的 @babel/runtime @babel/polyfill
  2. 須要一個插件的支持 @babel/plugin-transform-runtime
module.exports = {
 module: {  rules: [{  test: /\.js$/,  use: [{  loader: 'babel-loader',  options: {  //=>轉換的語法預設(ES6->ES5)  presets: [  "@babel/preset-env"  ],  //=>基於插件處理ES6/ES7中CLASS的特殊語法  plugins: [  ["@babel/plugin-proposal-decorators", {  "legacy": true  }],  ["@babel/plugin-proposal-class-properties", {  "loose": true  }],  "@babel/plugin-transform-runtime"  ]  }  }], //=>, "eslint-loader"  //=>設置編譯時忽略的文件和指定編譯目錄  include: path.resolve(__dirname, 'src'),  exclude: /node_modules/  }]  } } 複製代碼

十3、分享

對於我來講的一個好消息吧,前天本身鼓足了勇氣加了本身膜拜的前端大神,雖然,尬聊了兩句(粉絲見到偶像是否是都是這樣🙈),可是也給了本身在前端路上的信心。激動的心情已經沒法有言語訴說😊

最後咱們你們一塊兒加油,期待有一天咱們均可以與膜拜的大神做爲同事😊

加油
加油
相關文章
相關標籤/搜索