webpack从入门到精通

1. package.json 项目清单文件

version //版本号
description  //描述
main  //主程序入口
script  //脚本
dependencies //依赖

2. .babelrc(babel的根配置文件)

3. script脚本

3.1. entry入口

上面的-f是文件名为entry

entry结构如下

dist是打包后生成的目录,也就是你运行npm run entry后生成的entry的压缩文件

在index.html里引入

<script type="text/javascript" src="/entry/dist/_index.js"></script>

然后在index.js里写

alert('i am index')

entry可以是:Object、Function、promise、String

3.1.1. entry为Object的情况如下:
//在webpack.config.js文件里

//对象前面的key就是你生成dist目录后对应的文件名
let base = {
  index: './index.js',
  index1: './index1.js'
}

module.exports = {
  entry:base,
   //这里指定了生成的目录前要加'_你上面对应的文件名.js',所以最后输出的dist下的文件是_index.js和_index1.js
  output: {
    filename: '_[name].js'
  }
}

运行

npm run entry

页面弹出'i am index'的弹窗

3.1.2. entry为Function
let base = {
  index: './index.js',
  index1: './index1.js'
}
function fn(){
  return base
}

module.exports = {
  entry:fn,
  output: {
    filename: '_[name].js'
  }
}
3.1.3. entry为promise
function fn(){
  return new Promise((resolve,reject)=>{
    resolve(base)
  })
}

module.exports = {
  entry:fn,
  output: {
    filename: '_[name].js'
  }
}
3.1.4. entry为String
let base = './index.js'

module.exports = {
  entry:base,
  output: {
    filename: '_[name].js'
  }
}

这里要注意如果是字符串dist目录生成的文件名,就会以默认的main开头,所以最后生成的dist目录为_main.js

3.2. output

output: {
  //导出目录
  path: path.resolve(__dirname, 'uuudist'),
  publicPath: "/output/uuudist/", // server-relative
  //包规范格式
  libraryTarget:'umd',
  library: "MyLibrary", 
  //文件名
  chunkFilename:'[chunkhash]_[name].js',
  //hash位数
  hashDigestLength:3,
  //导出文件 
  //hash ==> webpack编译过程
  // chunkhash => webpack对每个文件的hash
  filename: '_[name][chunkhash].js'
}

path用于定义导出目录的名称
你上面的第二个参数字符串就是你打包生成的目录名,你写的uuudist那就会生成一个uuudist的目录

filename:生成的文件名的格式
其中[name]是拿到你entry里面的对象里的key,而[chunkhash]是webpack编译的时候会认为每一个文件都是一个chunk,他会有一个hash算法来标识每一个文件,然后通过hashDigestLength来定义hash取多少位,使用[chunkhash]主要是用来作为时间戳解决缓存问题,要注意每次文件内容的改变会引起hash值的改变,所以文件不会去重是增量的,比如:原来目录下只有一个index1生成的文件


当你改变index1.js里的内容的时候,会重新对你当前dist下的目录重新生成一遍不同hash的文件

//包规范,一般默认使用umd,提供各种兼容模式
libraryTarget:'umd',
//当你写umd的时候就相当于
if(typeof exports === 'object' && typeof module === 'object')
    module.exports = factory();
else if(typeof define === 'function' && define.amd)
    define([], factory);
else if(typeof exports === 'object')
    exports["MyLibrary"] = factory();
else
    root["MyLibrary"] = factory();
library: "MyLibrary", 
//就相当于变量var MyLibrary,
//直接通过MyLibrary就可以拿到你包的导出内容

hash包括 hash和chunkhash

hash是整个webpack编译过程,也就是说你所有的文件都会生成一个同样的hash值
比如:

filename: '[hash]_[name].js'

最后生成的目录里的文件如下:

chunkhash就像前面说的是webpack对每一个文件都有一个自己的hash值

filename: '[chunkhash]_[name].js'

chunkFilename:异步加载的文件名字
publicPath:异步加载文件的路径(前缀)

在index.js里
//异步加载
//第一个参数是依赖,第二个是function,第三个是文件名
require.ensure([],(require)=>{
    require('./index1.js')
},'dynamic')
//当你要使用异步加载文件的时候就需要使用'/output/uuudist/异步加载的文件名'
publicPath: "/output/uuudist/",
//这里的[chunkhash]对应一个hash值,[name]对应你上面异步加载的第三个参数文件名'dynamic'
chunkFilename:'[chunkhash]_[name].js',

通过定义publicPath,和chunkFilename会在output/uuudist目录下生成一个异步加载的文件

3.3. split

实现文件模块化


可以通过require和import实现模块化引入,下面在index.js里引入split.js里的内容

//split.js
console.log('I am a split')
//index.js
console.log('I am index')
import './split.js'
//require('./split')

最后只要引入index.js就能同时打印出I am a split和I am index

3.4. module

module.exports = {
  entry:base,
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },
  module:{
    rules:[
    // Conditions, Results and nested Rules.
        {
        test: /\.jsx?$/,
        
        exclude: [
          'node_modules'
        ],
        // flags to apply these rules, even if they are overridden (advanced option)

        //webpack1的语法
        // loader: "babel-loader",

        // rule.use是数组形式和rule.loaders是它的别名
        use:[{
           loader: "babel-loader",
        }]
      },
    ]
  }
};

module是一个对象,对象里面是一个rules规则数组,数组里面又是一个对象,他每次都会对文件走一遍rules,先进行test正则匹配看一下这个文件的文件名满足不满足这个正则,满足的话就开始走use这个数组,使用loader,这个loader就是使用babel-loader来转码成浏览器兼容的js,当发现node_modules里面的js的时候就不会用loader去转码,因为node_modules里面的文件都有一个预处理entry==>loaders==>webpack===>output,所以你即使不通过loader来转码,webpack也会去转的

3.5. resolve

resolve.alias用来处理别名,更容易维护

比如你要在

当前目录结构下的index.js里引入test/test/test.js

那么你就要这么写

//index.js
require('./test/test/test.js')

这样如果多个文件里都要使用它的话,你写起来就会很复杂,这时候我们就可以通过resolve里的alias来实现,alias是一个对象,里面是你定义的别名和路径

module.exports = {
  resolve:{
    alias:{
      //这里的路径只能是绝对路径  
      test:path.resolve(__dirname,'test/test/test.js')
    }
  },
  //entry ==> rules ===> webpack ==> output
  module:{
    rules:[
        {
        test: /\.jsx?$/,
        
        exclude: [
          'node_modules'
        ],
        use:[{
           loader: "babel-loader",
        }]
      },
    ]
  }
};

然后你再引入这个test.js只需引入你定义的别名就行

//index.js
require('test')
//就相当于require('./test/test/test.js')

3.6. devtool

通过dectool:'source-map'可以实现在源文件中debugger
比如你在开发的时候在你的源文件index.js里写了一个debugger

//index.js
import test  from 'test';
debugger;
console.log(test());

如果你不在webpack里面写dectool:'source-map'的话,你打包运行后就会发现它是在你打包生成的文件里debugger了



而我们都是希望在我们编写的文件里测试,所以我们就需要加

module.exports = {
  // https://webpack.js.org/configuration/devtool/#devtool
  devtool:'source-map',
  // https://webpack.js.org/configuration/target/#target
};

再次运行,你就会发现确实在我们的源文件中debugger了

3.7. loaders 预处理

module:{
    //entry => loaders ==> webpack ==> output
    rules:[
            {
                test: /\.js[x]?$/,
                exclude: /node_modules/,
                use: {
                  loader:'babel-loader'
                }
            },
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use:{
                        loader:'css-loader',
                        options: {
                           sourceMap: true
                        }
                    }
                })
            },
            {
                test: /\.less$/,
                use: ExtractTextPlugin.extract({
                    fallback:'style-loader',
                    use:['css-loader',{
                        loader:'less-loader',
                        options: {
                           sourceMap: true
                        }
                    }]
                })
            },
            {
                test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                    fallback:'style-loader',
                    use:['css-loader',{
                        loader:'sass-loader',
                        options: {
                           sourceMap: true
                        }
                    }]
                })
            },
            {
                test: /\.(png|jpg|jpeg|gif|woff|woff2|ttf|eot|svg|swf)$/,
                use: {
                    loader:'file-loader',
                    options:{
                        name:'[name]_[sha512:hash:base64:7].[ext]'
                    }
                }
            },
            {
                test: /\.html/,
                use:{
                    loader:"html-loader",
                    options:{
                        minimize: false,
                        attrs:false
                    }
                }
            }
    ]
  }

options是对每一个loader进行个性化配置

3.8. plugins

对webpack编译的生命周期做一个hook

module.exports = {
  plugins:[
            new webpack.ProvidePlugin({
                $: 'jquery'
            }),
            new WebpackNotifierPlugin({
                title: 'Webpack 编译成功',
                contentImage: path.resolve(process.cwd(), './img/avatar.jpeg'),
                alwaysNotify: true
            }),
            new ExtractTextPlugin({
                filename: "[name].css",
                disable: false,
                allChunks: true
            }),
            new webpack.optimize.CommonsChunkPlugin({
                name: 'common',
                minChunks: Infinity
            })
  ],
  module:{
    rules:[
            {
                test: /\.js[x]?$/,
                exclude: /node_modules/,
                use: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use:{
                        loader:'css-loader',
                        options: {
                           sourceMap: true
                        }
                    }
                })
            },
            {
                test: /\.less$/,
                use: ExtractTextPlugin.extract({
                    fallback:'style-loader',
                    use:['css-loader',{
                        loader:'less-loader',
                        options: {
                           sourceMap: true
                        }
                    }]
                })
            },
            {
                test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                    fallback:'style-loader',
                    use:['css-loader',{
                        loader:'sass-loader',
                        options: {
                           sourceMap: true
                        }
                    }]
                })
            },
            {
                test: /\.(png|jpg|jpeg|gif|woff|woff2|ttf|eot|svg|swf)$/,
                use: {
                    loader:'file-loader',
                    options:{
                        name:'[name]_[sha512:hash:base64:7].[ext]'
                    }
                }
            },
            {
                test: /\.html/,
                use:{
                    loader:"html-loader",
                    options:{
                        minimize: false,
                        attrs:false
                    }
                }
            }
    ]
  }
};

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容