平常工做webpack必備姿式(一)

爲何用webpack這玩意兒?

你們有沒有看過jquery框架的源碼?知道它源碼有多少行嗎?css

1.x版本的都在10000行以上。你們試想若是在開發時候這1萬多行代碼都在一個文件,那文件這麼長,開發測試的時候會有多麻煩。因而乎有人就開始想了,開發的時候把代碼按照不一樣的功能分紅不一樣的文件,方便於開發調試,到發佈的時候在把代碼合併到一塊兒就OK了,這個把代碼合併到一塊兒的玩意兒就是咱們今天須要探討的打包工具,也是它的最主要的功能之一:代碼合併。html

在咱們前端開發中,你們必定還遇到過如下一些常見問題,諸如:前端

前端樣式採用less或者scss開發,最新的es6語法,但是瀏覽器並不能識別(備註:能夠引入轉換腳本解決)node

項目引入的css和js等文件太多,文件體積太大,勢必會引發瀏覽器屢次請求服務器加載資源引發速度慢,能不能減小文件數量和文件體積呢?jquery

這就是今天的主角webpack要作的事情,看下去你就會知道如何使用!webpack

webpack安裝和入門案例

先來看看安裝:es6

//初始化安裝目錄
npm init -y

安裝webpack和webpack-cli(4.x以上版本須要安裝webpack-cli)
npm install --save-dev webpack
npm install --save-dev webpack-cli

安裝完咱們來體驗一下入門案例:
企業微信截圖_20200314102945.pngweb

第一個案例整體目錄如圖所示:正則表達式

第一步:創建src文件,在src文件下新建文件取名爲index.jsnpm

//index.js內容以下
console.log("hello webpack");

第二步:使用webpack打包上面的文件

npx webpack

自此變自動生成了如圖所示的dist目錄和打包後的main.js文件

第三步:驗證打包後的main.js文件是否正確

方法一:用html文件測試,咱們的例子是會在控制檯輸出"hello webpack"字符串

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>webpack</title>        
    </head>
    <body>
    </body>
    <script src="./main.js"></script>
</html>

方式二:由於咱們這裏只用到了js代碼,能夠進入到打包後的文件夾,用node來運行代碼

node main.js

編譯後的文件默認是生產環境,代碼通過壓縮因此直接看不懂,若是你但願能看懂編譯後的js文件,或者你但願修改一下編譯後的文件名稱等,能夠經過給webpack提供配置文件的方式來解決:

webpack配置文件

第一步:在項目目錄下創建文件webpack.config.js

文件內容以下

let path =  require('path'); //webpack是node寫出來的,path是node的語法
 
module.exports = {
    mode:'development', //編譯環境改爲是development(開發模式)
    entry:'./src/index.js',    //須要編譯的源文件目錄
    output:{                //編譯後的目錄
        filename:'configTest.js',    //編譯後的文件名稱
        path:path.resolve(\_\_dirname,'build')    //編譯後的路徑,必須是絕對路徑
    }
}

第二步:編譯打包文件和測試生成的文件方式和上一步相同,不過注意生成的文件名稱變了

npx webpack  //和以前的編譯方式同樣

附上一張最終效果圖:
企業微信截圖_20200314110206.png

配置文件名稱能不能改?我公司的項目在打包編譯的時候用的是npm run build是怎麼回事?

好比我如今將webpack配置文件名改爲了webpack.configOther.js,那麼我在運行的時候能夠經過指定配置文件名稱的方式運行,以下:

npx webpack --config webpack.configOther.js

可是上述運行代碼的方式明顯太長,看着很不舒服,只需一步就能夠搞定:

//打開package.json文件,添加以下key-value值
"scripts": {
    "build": "webpack --config webpack.configOther.js"
  },

接下來咱們就能夠經過npm run build的方式來編譯咱們的代碼了。寫在package.json文件scripts裏的內容能夠經過npm run 腳本名的方式來調用。

webpack開發環境搭建

上面咱們測試本身寫的webpack用法對不對,須要想辦法運行編譯後的文件才行,有沒有以爲很麻煩?咱們編譯後的文件還須要手動在新建的html文件裏面引入,每更改一次文件要想看更新後的效果都還須要在次刷新頁面。。。問題多的我已經寫不下去了,咱們來看看解決之道吧。

webpack插件的概念:一些第三方項目工具包,webpack中引入這玩意可以對整個工程全部代碼進行處理,豐富webpack的功能。

html-webpack-plugin插件:引入這位老兄,咱們的項目能夠自動在編譯後的路徑中生成html文件,而且自動引用編譯後的js文件。

devServer:這個工具能夠幫助咱們實現熱開發,它能在本地啓動http服務,咱們經過瀏覽器訪問項目。咱們的項目代碼會被加載到內存中。咱們修改了本地的代碼,不須要重啓服務,項目會自動更新爲最新狀態。

介紹了這麼多咱們就來實際操做一遍:
第一步:安裝依賴包

//安裝html-webpack-plugin
npm install --save-dev html-webpack-plugin
//安裝webpack-dev-server
npm install webpack-dev-server --save-dev

第二步:修改webpack.config.js文件

let path =  require('path'); //webpack是node寫出來的,path是node的語法
let HtmlWebpackPlugin = require('html-webpack-plugin'); //HTML編譯插件

module.exports = {
    //開發環境
    devServer: {
        contentBase: './build',        //咱們把編譯後的目錄build指定爲開發環境
        compress: true,    //是否展現進度條
        port: 9000    //開發環境啓動端口
    },

    mode:'development', //編譯環境改爲是development(開發模式)
    entry:'./src/index.js',    //須要編譯的源文件目錄
    output:{                //編譯後的目錄
        filename:'bundle.[hash].js',    //編譯後的文件名稱
        path:path.resolve(__dirname,'build')    //編譯後的路徑,必須是絕對路徑
    },

    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html', //須要編譯的html源文件
            filename:'indexTest.html',         //編譯後的文件名
            minify:{
                collapseWhitespace:true     //編譯後的html文件去掉空格
            }
        })
    ]
}

上述devServer是開發環境熱加載功能的部分,HtmlWebpackPlugin是自動打包html文件的插件用法,注意template是須要有一個源文件的,filename指定編譯後的目標文件名稱(我這裏隨意指定的,通常取名爲index.html)

//./src/index.html源文件,我這裏沒有指定js文件名稱
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>webpack</title>        
    </head>
    <body>        
    </body>    
</html>

第三步:查看html-webpack-plugin編譯後的效果

//編譯查看效果
npm run build

企業微信截圖_20200314163024.png

我在上面的配置中指定了,生成的js文件名稱爲hash方式,這樣能夠防止文件沒有刷新和緩存引發的問題,咱們在源html文件中並未指定生成的js文件會自動引入。

第四步:配置開發環境
就像以前配置npm run build同樣,咱們配置一下開發環境運行方式爲npm run dev

"scripts": {
    "build": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server"
  },

接下來咱們就能夠經過npm run dev來開發咱們的項目啦。

爲了讓瀏覽器看到效果,咱們在經過js文件想html中輸入一段文字

//修改咱們的index.js文件
document.body.innerHTML= 'devServer and HtmlWebpackPlugin';

在瀏覽器中輸入項目路徑便可訪問:

http://localhost:9000/indexTest.html
//若是生成的文件名爲index.html.可省略文件名,直接用以下方式調用
http://localhost:9000

接下來咱們能夠隨意修改index.js文件的內容,保存以後頁面會當即刷新最新數據

樣式處理

開發中避免不了須要給頁面添加css樣式,但是webpack是node開發的,不認識css文件,咱們如何讓它認識呢?

有一個常接觸到朋友叫loader,好比如今有一個css文件咱們須要解析怎麼辦?這個時候咱們只要在webpack中添加上style-loader css-loader就可讓webpack識別css文件了。再好比咱們css用的是less語法,咱們只要在webpack中添加less-loader就又能夠用了。看到了嗎?loader它就是用於專門處理一類文件的,功能比較單一,一種loader一般只處理一種文件。咱們看下示例:

第一步:安裝依賴包

//安裝解析css的依賴包
npm install --save-dev style-loader css-loader
//安裝解析less的依賴包(不用less可不安裝)
npm install less less-loader --save-dev

第二步:準備好樣式文件

//001.css文件
@import './002.css';
body{
    background-color: green;
}

//002.css文件
body{
    color:red;
}

//003.less文件
body{
    font-size:30px;
}

第三步:要在項目中引入這些樣式才能看到效果(主入口文件中引入)

//我這裏的主入口文件一直都是index.js(webpack配置文件中的entry:'./src/index.js'選項)
require('./001.css')
require('./003.less')
document.body.innerHTML= 'loader';

第四步:在配置文件中告訴webpack如何解析,添加新的屬性(可參考結束語的整個配置文件)

//模塊
module:{
    //規則:loader特色,但願單一
    //loader的用法,字符串只適用於一個loader,多個loader須要用[]
    //loader的順序,默認是從右向左執行
    //loader還能夠寫出對象的方式(好處是能夠添加更多的參數)
    rules:[
        {
            test:/\.css$/,
            use:[
                //css-loader用於機械@import這種語法
                //style-loader把css插入到頁面中
                {
                    loader:'style-loader'
                },
                'css-loader'
            ]
        },

        {
            test:/\.less$/,
            use:[
                'style-loader',
                'css-loader',
                'less-loader' //less轉換成css文件
            ]
        }
    ]
}

loader須要放到module下的rules中,一個項目中有各類文件須要解析,所以rules是一個數組,能夠配置不一樣的解析規則。每個loader配置包含test屬性,是一個正則表達式用於匹配文件格式;use則用於指定具體的解析loader。

咱們來查看最終的效果圖:
企業微信截圖_20200314182910.png

備註:抽離css可使用mini-css-extract-plugin

轉換es6語法

如今的前端開發避免不了要用到ES6,不過您不瞭解ES6和babel請跳過本部分知識。

第一步:安裝相應的loader

npm install -D babel-loader @babel/core @babel/preset-env webpack

第二步:在webpack配置文件中module下rules中添加文件過濾規則

{
    test:/\.js$/,
    use:{
        loader:'babel-loader',
        options:{
            presets: ['@babel/preset-env'] //指定將ES6轉換爲ES5
        }
    }
}

搞定完這兩步就能夠在項目中使用ES6語法了,想測試的話能夠將mode修改成development,而後在編譯文件中查看是否有轉換成ES5語法。

eslint校驗

eslint是項目代碼校驗工具,可以在項目運行啓動以前檢查項目語法錯誤,若是對eslint不是很瞭解,請先點擊連接看下相關文檔

第一步:安裝eslint和loader

npm install eslint eslint-loader --save-dev

第二步:在webpack配置文件中module下rules中添加文件過濾規則

{
    test: /\.js$/,
    exclude: /node_modules/, //去掉不須要校驗的模塊
    loader: 'eslint-loader', 
    options: {
      failOnError: true,
    },
},

第三步:在項目目錄下添加.eslintrc.json文件(注意文件名稱前有英文點號)

//.eslintrc.json文件內容,能夠根據實際須要自行配置
{
    "parserOptions": {
        "ecmaVersion": 5,
        "sourceType": "script",
        "ecmaFeatures": {}
    },
    "rules": {
        "constructor-super": 2,
        "for-direction": 2,
        "getter-return": 2,
        "no-async-promise-executor": 2,
        "no-case-declarations": 2,
        "no-class-assign": 2,
        "no-compare-neg-zero": 2,
        "no-cond-assign": 2,
        "no-const-assign": 2,
        "no-constant-condition": 2,
        "no-control-regex": 2,
        "no-debugger": 2,
        "no-delete-var": 2,
        "no-dupe-args": 2,
        "no-dupe-class-members": 2,
        "no-dupe-keys": 2,
        "no-duplicate-case": 2,
        "no-empty": 2,
        "no-empty-character-class": 2,
        "no-empty-pattern": 2,
        "no-ex-assign": 2,
        "no-extra-boolean-cast": 2,
        "no-extra-semi": 2,
        "no-fallthrough": 2,
        "no-func-assign": 2,
        "no-global-assign": 2,
        "no-inner-declarations": 2,
        "no-invalid-regexp": 2,
        "no-irregular-whitespace": 2,
        "no-misleading-character-class": 2,
        "no-mixed-spaces-and-tabs": 2,
        "no-new-symbol": 2,
        "no-obj-calls": 2,
        "no-octal": 2,
        "no-prototype-builtins": 2,
        "no-redeclare": 2,
        "no-regex-spaces": 2,
        "no-self-assign": 2,
        "no-shadow-restricted-names": 2,
        "no-sparse-arrays": 2,
        "no-this-before-super": 2,
        "no-undef": 2,
        "no-unexpected-multiline": 2,
        "no-unreachable": 2,
        "no-unsafe-finally": 2,
        "no-unsafe-negation": 2,
        "no-unused-labels": 2,
        "no-unused-vars": 2,
        "no-useless-catch": 2,
        "no-useless-escape": 2,
        "no-with": 2,
        "require-atomic-updates": 2,
        "require-yield": 2,
        "use-isnan": 2,
        "valid-typeof": 2
    },
    "env": {
        "browser": true,
        "node": true
    }
}

第四步:編寫文件,開啓項目或者編譯項目檢查eslint是否正確配置

//在index.js文件中添加以下代碼啓動項目,能夠看到如圖所示的錯誤
var foo = bar;

企業微信截圖_20200314234851.png

即:
'foo' is assigned a value but never used no-unused-vars
'bar' is not defined no-undef

引入第三方插件和全局變量

有時候可能須要在項目中引入jquery等第三方庫,該怎麼作呢?

首先沒必要多說確定是引入jquery

npm run jquery

而後能夠直接在想用jquery的地方引入jquery便可

//node的方式
let $ =  require('jquery');
//ES6的方式
import $ from 'jquery'

不過上述引入jquery方式都只是在單個模塊內部,也就是說每一個模塊文件想用jquery都得從新引入一次jquery才行,不能經過window獲取jquery對象。但若是你就但願經過window.$來用怎麼辦呢?

方式一:經過expose-loader插件把$暴露到全局window對象上

//安裝expose-loader
npm run expose-loader
//在文件中引入jquery(不可缺乏)
let $ =  require('jquery');
//在module下rules中添加文件過濾規則
{
    test:require.resolve('jquery'),
    use:'expose-loader?$'
},
//至此能夠console.log(window.$)獲取全局$對~~~~象

方式二:一次性在全部模塊中注入$對象,這種方式並不會jquery暴露到window對象上,可是每一個模塊在使用$的時候也不須要在引用jquery了

//在配置文件中引入webpack
let webpack = require('webpack');
//在配置文件中plugins添加以下插件
new webpack.ProvidePlugin({
            $:'jquery'~~~~
        })

方式三:直接在頁面的<script>標籤中引入js文件,不經過webpack打包的方式。

引入圖片和路徑處理

JS引入圖片

第一步:安裝依賴loader

//圖片屬於文件
npm install --save-dev file-loader

第二步:在配製文件中module下的rules中添加規則

{
    test: /\.(png|svg|jpg|gif)$/,
    use: 'file-loader'
},

第三步:在項目目錄下添加圖片

import imgLogo from './0.jpg';
let image = new Image();
image.src = imgLogo;
document.body.appendChild(image);

CSS中引入圖片

第一步:在css中引入圖片

body{
    background: url('./0.jpg');
}

第二步:在入口文件中引入css文件(index.js文件)

import('./001.css')

備註:html-withimg-loader能夠實現html中直接使用img標籤src加載圖片,請自行學習~

文件打包路徑

在開發過程當中,咱們應該將全部圖片都放到img目錄下,能夠經過修改上面的loader配置來實現

{
    test: /\.(png|svg|jpg|gif)$/,
    use: {
        loader:'file-loader',
        options:{
            outputPath:'img/' //建立img目錄
        }
    }
},

或許還會根據須要將全部文件放到麼個域名下,咱們能夠在編譯的時候,修改目錄輸出,添加publicPath屬性便可。

//編譯後的目錄
output:{                
        filename:'bundle.[hash].js',    //編譯後的文件名稱
        path:path.resolve(__dirname,'build'),    //編譯後的路徑,必須是絕對路徑
        publicPath:'http://www.baidu.com/~~~~' //編譯到麼個域名下
    },

結束語

都目前爲止整個項目配置文件內容以下,可根據須要進行選用:

let path =  require('path'); //webpack是node寫出來的,path是node的語法
let HtmlWebpackPlugin = require('html-webpack-plugin'); //HTML編譯插件
let webpack = require('webpack');

module.exports = {
    //開發環境
    devServer: {
        contentBase: './build',        //咱們把編譯後的目錄build指定爲開發環境
        compress: true,    //是否展現進度條
        port: 9000    //開發環境啓動端口
    },

    mode:'development', //編譯環境改爲是development(開發模式)
    entry:'./src/index.js',    //須要編譯的源文件目錄
    output:{                //編譯後的目錄
        filename:'bundle.[hash].js',    //編譯後的文件名稱
        path:path.resolve(__dirname,'build'),    //編譯後的路徑,必須是絕對路徑
        //publicPath:'http://www.baidu.com'
    },

    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html', //須要編譯的html源文件
            filename:'index.html',         //編譯後的文件名            
        }),
        new webpack.ProvidePlugin({
            $:'jquery'
        })
    ],
    
    //模塊
    module:{
        //規則:loader特色,但願單一
        //loader的用法,字符串只適用於一個loader,多個loader須要用[]
        //loader的順序,默認是從右向左執行
        //loader還能夠寫出對象的方式(好處是能夠添加更多的參數)
        rules:[           
            // {
            //     test: /\.js$/,
            //     exclude: /node_modules/, //去掉不須要校驗的模塊
            //     loader: 'eslint-loader', 
            //     options: {
            //       failOnError: true,
            //     },
            // },

            {
                test:require.resolve('jquery'),
                use:'expose-loader?$'
            },

            {
                test:/\.css$/,
                use:[
                    //css-loader用於機械@import這種語法
                    //style-loader把css插入到頁面中
                    {
                        loader:'style-loader'
                    },
                    'css-loader'
                ]
            },

            {
                test:/\.less$/,
                use:[
                    'style-loader',
                    'css-loader',
                    'less-loader' //less轉換成css文件
                ]
            },

            {
                test:/\.js$/,
                use:{
                    loader:'babel-loader',
                    options:{
                        presets: ['@babel/preset-env'] //指定將ES6轉換爲ES5
                    }
                }
            },

            {
                 test: /\.(png|svg|jpg|gif)$/,
                use: {
                    loader:'file-loader',
                    options:{
                        outputPath:'img/'
                    }
                }
            },
            
        ]
    }
}
相關文章
相關標籤/搜索