webpack學習筆記

kumayato發表於2017-04-26
  • 今天在慕課網裡學習了webpack深入與實戰的課程,收穫很多。因為現在webpack已經是2.0的版本了,中間入了一些坑不過都一一解決了。具體的可以檢視webpake2.0的中文文件。

  • webpack2.0的中文文件 : 感謝大牛們的無私奉獻,我找到工作一定給你們贊助。

  • 以下是學習筆記的整合。

webpack一個簡單的例項

第一步:初始化npm,下載webpack,html-webpack-plugin等外掛

  • html-webpack-plugin:npm官網上這個外掛的文件,這個外掛怎麼用,以及它有哪些屬性上面都解釋的很清楚。

  • 我的檔案目錄
    這裡寫圖片描述

第二步:在根目錄新建一個webpack.config.js的檔案,用來配置webpack打包時的一些必要資訊。

// 模組引用
var path = require('path');
var webpackHtmlPlugin  = require('html-webpack-plugin');

module.exports = {
    // 入口檔案(這裡傳入的是一個物件,打包後會分別生成兩個js檔案)
    entry: {
        main : './src/script/main.js',
        base : './src/script/base.js'
    },

    // 出口檔案
    output: {
        path: path.resolve(__dirname,'dist'),
        //分別會生成兩個js檔案,都是以名字+hash值的形式命名。
        filename: 'js/[name]-[hash].js'

    },
    // 注意:在path裡所有輸出的檔案目標路徑,必須是絕對路徑(這裡使用node.js的path模組);

    // 外掛
    plugins : [
        // 初始化外掛,這個外掛會為我們自動生成一個已經插入好js指令碼檔案的html檔案。
        new webpackHtmlPlugin({
            // 指定生成的html檔案的名字
            filename : 'index-[hash].html',

            //生成的檔案以根目錄下的index.html為模板
            template : 'index.html', 

            //指定生成的js檔案是在head裡還是在body裡面,不寫預設在body裡面
            inject : 'head'
        })
    ]
};
  • ==注意==:有個地方困惑了很久,一開始是按照官方文件來寫,在output的path的指定了如下路徑,
  output: {
        path: './dist',
        filename: 'js/[name]-[hash].js'
    }
  • 不論怎麼試都報錯,給出的原因是./dist不是一個絕對路徑。後來才知道,path裡面只可以使用絕對路徑。解決的方法有兩種,推薦我上面寫的示例程式碼,用node.js的path模組,在nodejs裡__dirname代表根目錄。另一種解決方式是把路徑寫在filename裡面。
 output: {
        path: __dirname,
        filename: './dist/js/[name]-[hash].js'
    }
  • 這樣寫不太好,因為所有生成的檔案都會在./dist/js/這個資料夾裡面,我們還有要依賴html-webpack-plugin外掛為我們自動生成一個已經插入了js指令碼的index檔案,這樣的話,包括index.html在內的所有檔案都會在同一個資料夾裡面。

第三步 全部完成好後在命令列輸入webpack即可。

  • 得到webpack為我們自動生成的指令碼檔案,和已經插入指令碼檔案的index.html檔案,並且他們並不在同一個資料夾中。

這裡寫圖片描述

  • 再把原index.html檔案和為我們自動生成的index+hash值.html的檔案做一個對比。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>哈哈哈</p>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<script type="text/javascript" src="js/main-696a2dbabb5a795721ca.js"></script>
<script type="text/javascript" src="js/base-696a2dbabb5a795721ca.js"></script>
</head>
<body>
<p>哈哈哈</p>
</body>
</html>
  • 會發現生成的檔案是基於原檔案的內容且自動為我們插入了指令碼檔案。

補充:我們可以在package.json裡給webpack指定一些引數。使用webpack打包的時候在命令列就能看到這些引數內容了。

  • 在scripts裡指定webpack和webpack.config.js檔案,我們要看到打包的過程,打包的模組,字型彩色,打包的原因等。
  "scripts": {
    "webpack" : "webpack --config webpack.config.js --progress --display-modules --colors --display-reasons"
  }
  • 配置好後輸入 npm run webpack 即可。

生成專案中的html頁面檔案

檔案結構

這裡寫圖片描述

例項程式碼

// 模組引用
var path = require('path');
var htmlWebpackPlugin  = require('html-webpack-plugin');

module.exports = {
    // 入口檔案
    entry: {
        'main' : './src/script/main.js',
        'a' : './src/script/a.js',
        'b' : './src/script/b.js',
        'c' : './src/script/c.js',
        'd' : './src/script/d.js'
    },

    // 出口檔案
    output: {
        path: path.resolve(__dirname,'dist'),
        filename: 'js/[name].js',
        // 給所有輸出檔案加上公共的地址頭,滿足上線要求。
        publicPath : 'http://kuma.com/'

    },
    // 注意: 在path裡所有輸出的檔案目標路徑,必須是絕對路徑(使用node.js的path模組);

    module: {
        loaders: [
            {
                test: /\.hbs$/,
                loader: 'handlebars-loader'
            },
        ]
    },
    // 外掛
    plugins : [
        // 初始化外掛,這個外掛會為我們自動生成一個已經插入好js指令碼檔案的html檔案。
        new htmlWebpackPlugin({
            // 指定生成的html檔案的名字
            filename : 'a.html',
            //生成的檔案以根目錄下的index.html為模板
            template : 'index.html',
            // 定義html檔案中的title
            title : '我是a',
            // 打包壓縮
            minify: {
                // 刪除註釋
                removeComments : true,
                // 刪除空格
                collapseInlineTagWhitespace : true,
                collapseWhitespace : true
            },
            chunks: ['main','a']
        }),
        new htmlWebpackPlugin({
            // 指定生成的html檔案的名字
            filename : 'b.html',
            //生成的檔案以根目錄下的index.html為模板
            template : 'index.html',
            // 定義html檔案中的title
            title : '我是b',
            // 打包壓縮
            minify: {
                // 刪除註釋
                removeComments : true,
                // 刪除空格
                collapseInlineTagWhitespace : true,
                collapseWhitespace : true
            },
            chunks: ['main','b']
        }),
        new htmlWebpackPlugin({
            // 指定生成的html檔案的名字
            filename : 'c.html',
            //生成的檔案以根目錄下的index.html為模板
            template : 'index.html',
            // 定義html檔案中的title
            title : '我是c',
            // 打包壓縮
            minify: {
                // 刪除註釋
                removeComments : true,
                // 刪除空格
                collapseInlineTagWhitespace : true,
                collapseWhitespace : true
            },
            chunks: ['main','c']
        }),
        new htmlWebpackPlugin({
            // 指定生成的html檔案的名字
            filename : 'd.html',
            //生成的檔案以根目錄下的index.html為模板
            template : 'index.html',
            // 定義html檔案中的title
            title : '我是d',
            // 打包壓縮
            minify: {
                // 刪除註釋
                removeComments : true,
                // 刪除空格
                collapseInlineTagWhitespace : true,
                collapseWhitespace : true
            },
            chunks: ['main','d']
        })
    ]
};

第一步 首先要引用模板handlebars-loader,將 Handlebars 轉移為 HTML。先下載handlebars-loader,然後按照 這裡說的方式來配置好模板。

  • 在module.exports = {}裡面加上這一段
module: {
        loaders: [
            {
                test: /\.hbs$/,
                loader: 'handlebars-loader'
            },
        ]
    }

第二步 在plugins中定義一些需要的資訊。

  • 這裡初始化了a,b,c,d四個htmlWebpackPlugin外掛,他們的作用都是相同的,就是為我們自動生成一個已經插入指令碼檔案的html檔案,初始化四個就會分別生成四個html檔案,名字分別為a.html,b.html,c.html,d.html。

  • 我們定義了title的內容,分別為”我是a/b/c/d。

  • minify屬性用於打包壓縮,它自帶很多屬性,具體的設定都可以在這裡查詢到。最好的方法還是去npm官網看html-webpack-plugin的文件。

  • chunks:定義我們需要引入的chunk,不需要的就不會被引入。例如:chunks: [‘main’,’a’];我們只需要新增mian和a的chunk。

  • excludeChunks:剔除我們不需要的chunk,用法同chunks。

第三步 在根目錄下的index.html檔案中使用<%= %>這樣的語法來獲取之前在plugins中定義好的資訊。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <!--獲取title的值-->
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<!--我是一行註釋,看看最後我還在不在-->
<!--獲取指令碼的src-->
<script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
</body>
</html>
  • 之後生成的html檔案每一個都會引用main這個chunk和他們在chunks裡面定義的chunk。

第四步 npm run webpack 看看生成了什麼

這裡寫圖片描述

  • 分別生成了4個html檔案,和a,b,c,d,main五個指令碼檔案。

  • 看看html檔案的內容,如下是a.html:

<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>我是a</title></head><body><script src="http://kuma.com/js/main.js"></script><script type="text/javascript" src="http://kuma.com/js/main.js"></script><script type="text/javascript" src="http://kuma.com/js/a.js"></script></body></html>
  • 內容進行了壓縮,且給title賦予了之前設定好的值,分別引入了兩個指令碼檔案,後面的b,c,d也是同理,就不一一貼上去了。

  • ==補充== : html-webpack-plugin有一個屬性叫inject,如果我們改為false,就不會自動在生成的html檔案中插入指令碼檔案,它的預設值是body,所以其實我們不需要在index.html的檔案裡對script進行<%= %>的設定,只要在chunks裡面定義的所需要的chunk,生成的html檔案裡會自動新增chunks裡面所需要的指令碼檔案。

  • 此時的index.html檔案如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <!--獲取title的值-->
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
  • 這裡拿a.html例項,生成的程式碼如下,自動新增了所需要的指令碼檔案a和main。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <!--獲取title的值-->
    <title>我是a</title>
</head>
<body>
<script type="text/javascript" src="http://kuma.com/js/main.js"></script>
<script type="text/javascript" src="http://kuma.com/js/a.js"></script> 
</body>
</html>

程式碼優化

  • 上述生成的指令碼檔案的src值是一個帶http協議的地址,這樣的話會拖慢執行的速度,下面提供一個==優化==的辦法,通過實現script標籤inline的插入。

  • github上面的示例程式碼

doctype html
html
  head
    meta(http-equiv="Content-type" content="text/html; charset=utf-8")
    title #{htmlWebpackPlugin.options.title}
  body
    each cssFile in htmlWebpackPlugin.files.css
      style !{compilation.assets[cssFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()}
    each jsFile in htmlWebpackPlugin.files.js
      script(type="text/javascript") !{compilation.assets[jsFile.substr(htmlWebpackPlugin.files.publicPath.length)].source()}
  • 具體的為什麼要這樣寫我也沒完全理解,我來說說我的一些理解。

    • compilation.assets 我們可以看成是打包編譯後的入口檔案物件,裡面有我們在entry裡定義的若干個chunk,都是以鍵值對的形式存在name : js路徑。

    • 因為我們的目標是要過濾掉publicPath裡面的內容。
      所以可以用:substr(htmlWebpackPlugin.files.publicPath.length)這個方法,通過傳入publicPath的長度,從而只取到publicPath內容之後的值。

    • htmlWebpackPlugin.files.chunks.main.entry就相當於是一個jsFile,可以看成是獲取到這個jsFile的key為main的值。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <!--獲取title的值-->
    <title><%= htmlWebpackPlugin.options.title %></title>
    <script type="text/javascript">
        <%=
        htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)
        %>
    </script>
</head>
<body>
</body>
</html>
  • 最後執行一下webpack看一下結果是什麼?
<script type="text/javascript">
        js/main.js
</script>
  • 可以看到我們在publicPath裡面設定的內容都被過濾掉了。

  • 現在按照文件上寫的,我們在head裡面引入main這個chunk,在body裡面引入其他的chunk,遍歷除了main以外的chunk。這裡只有main這個chunk是以inline的方式引入。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <!--獲取title的值-->
    <title><%= htmlWebpackPlugin.options.title %></title>
    <script type="text/javascript">
        <%=
        compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source()
        %>
    </script>

</head>
<body>
<% for(var k in htmlWebpackPlugin.files.chunks){ %>
    <% if (k !== 'main'){ %>
        <script type="text/javascript" src="<%= htmlWebpackPlugin.files.chunks[k].entry %>"></script>
    <% } %>
<% } %>
</body>
</html>
  • 此時的webpack.config.js檔案,我們只生成一個html檔案。裡面引入main和abcd五個指令碼檔案。
// 模組引用
var path = require('path');
var htmlWebpackPlugin  = require('html-webpack-plugin');

module.exports = {
    // 入口檔案
    entry: {
        'main' : './src/script/main.js',
        'a' : './src/script/a.js',
        'b' : './src/script/b.js',
        'c' : './src/script/c.js',
        'd' : './src/script/d.js'
    },

    // 出口檔案
    output: {
        path: path.resolve(__dirname,'dist'),
        filename: 'js/[name].js',
        // 給所有輸出檔案加上公共的地址頭,滿足上線要求。
        publicPath : 'http://kuma.com/'

    },
    // 注意: 在path裡所有輸出的檔案目標路徑,必須是絕對路徑(使用node.js的path模組);

    module: {
        loaders: [
            {
                test: /\.hbs$/,
                loader: 'handlebars-loader'
            },
        ]
    },
    // 外掛
    plugins : [
        // 初始化外掛,這個外掛會為我們自動生成一個已經插入好js指令碼檔案的html檔案。
        new htmlWebpackPlugin({
            // 指定生成的html檔案的名字
            filename : 'main.html',
            //生成的檔案以根目錄下的index.html為模板
            template : 'index.html',
            // 定義html檔案中的title
            title : '我是main',
            // 打包壓縮
            chunks: ['main','a','b','c','d'],
            // 不會自動插入指令碼檔案
            inject : false
        })
    ]
};
  • webpack後生成的檔案,body裡面就是這樣,head裡面inline的引用太長了,我就不貼出來了。
<body>
<script type="text/javascript" src="http://kuma.com/js/d.js"></script>
<script type="text/javascript" src="http://kuma.com/js/c.js"></script>
<script type="text/javascript" src="http://kuma.com/js/b.js"></script>
<script type="text/javascript" src="http://kuma.com/js/a.js"></script>
</body>

相關文章