webpack

一、webpack3.x.x基本介绍

  • 1-1 webpack基本介绍
    webpack的概念和作用
    模块打包器
    代码分割
    代码文件打包
    loader加载
    commonjs规范
    模块热更新
    适用于大型项目

  • 1-2 webpack安装和命令
    安装
    npm install webpack --save-dev

例子:
新建hello.js执行命令 webpack hello.js hello.bundle.js ,会生成hello.bundle.js文件,观察文件中的内容,可以看到webpack在文件中生成了许多其他代码

新建world.js并在hello.js文件中require('./world.js'),再执行命令webpack hello.js hello.bundle.js,观察hello.bundle.js文件中的内容

新建style.css,在样式表中随便新建几行样式html,body{background: #f00;},在hello.js文件中require('style-loader!css-loader!./style.css'),执行命令webpack hello.js hello.bundle.js(注意:webpack加载css需要用到css-loader,行内样式需要用到style-loader。安装loader npm install css-loader style-loader --save-dev)
css-loader用来将style.css打包到hello.bundle.js文件中,使webpack能处理.css文件,如果将css-loader处理后的文件,引入到页面中后(在这个例子中引入页面的是hello.bundle.js),style-loader则会将style.css中的样式以<style></style>的形式插入到head

如果在页面中没有加载这两个loader也可以在命令行中直接加载loader webpack hello.js hello.bundle.js --module-bind "css=style-loader!css-loader"

输入webpack可以查看webpack中有哪些配置项
webpack hello.js hello.bundle.js --watch 用来监听文件,如果文件有变化则自动编译打包
webpack hello.js hello.bundle.js --progress 用来查看打包的进度
webpack hello.js hello.bundle.js --display-modules 用来查看打包的模块
webpack hello.js hello.bundle.js --display-resons 用来查看打包的原因

二、webpack基本配置

  • 2-1建立项目的webpack配置

例子:
webpack-demo目录下新建以下文件

webpack-demo
-dist
--js
-src
--script
--style
-index.html
-package.json
-webpack.config.js

webpack.config.js

module.exports = {
    entry: './src/script/main.js',//入口文件
    output: {
        path: './dist/js',//输出路径
        filename: 'bundle.js'//输出文件名
    }
}

运行 webpack 会在dist下的js目录下生成bundle.js

可在package.jsonscript字段中添加配置webpack

"scripts": {
    "webpack":"webpack --config webpack.config.js --progress --display-modules --colors --display-reasons"
},
  • 2-2webpack配置的entryoutput
    entry是入口文件

entry可以是一个字符串

entry:'a.js'
    {
        context: __dirname + "/app",
        entry: "./entry",
        output: {
            path: __dirname + "/dist",
            filename: "bundle.js"
        }
    }

entry可以是一个数组
数组中的文件一般是有相互依赖关系的,或者是没有互相依赖关系但是又处于某些原因需要将它们打包在一起

entry:['a.js','main.js']

entry可以是一个对象({key:value})常用于多页面(多入口)的情况下配置
key
key可以是简单的字符串,比如:’app’, ‘main’,’entry-1’等。并且对应着output.filename配置中的[name]变量key还可以是路径字符串。此时webpack会自动生成路径目录,并将路径的最后作为[name]。这个特性在多页面配置下也是很有用的

entry: {
    'path/of/entry': './deep-app.js',
    'app': './app.js'
},
output: {
    path: './output',
    filename: '[name].js'
}

value
value如果是字符串,而且必须是合理的node require函数参数字符串。比如文件路径:’./app.js’(require(‘./app.js’));比如安装的npm模块:’lodash’(require(‘lodash’))
value如果是数组,则数组中元素需要是上面描述的合理字符串值。数组中的文件一般是没有相互依赖关系的,但是又处于某些原因需要将它们打包在一起。比如:

output: {
    path: _dirname+'/built',//输出路径
    filename: '[name].js'//输出文件名
    filename: '[name]-[hash].js'//输出文件名
    filename: '[name]-[chunkhash].js'//输出文件名
}
entry:{
    page1:'./page1'
    page2:['entry1.js','entry2.js']
}

entry是多入口的情况下,output也应该是多个输出 filename有三个可选参数 [name][hash][chunkhash]

output: {
    path: _dirname+'/built',//输出路径
    filename: '[name].js'//输出文件名
}

注意,在不同的版本下可能会报路径不是绝对路径的错误,解决办法为

var path = require('path');
module.exports = {
    entry: [url('src/script/main.js'), url('src/script/a.js')],
    output: {
        path: url('./dist/js/'),
        filename: 'bundle.js'
    }
}
function url(url) {
    return path.resolve(__dirname, url)
}

三、生成项目中的html文件

  • 3-1自动化生成项目中的html文件(上)

安装
html-webpack-plugin(这里有个坑就是,如果在全局安装webpack,在运行npm run webpack之前需要运行 npm link webpack)
自动生成html的意义在于,html中引用的js文件好多都是webpack打包之后生成的,生成的文件名和目录都有可能改变,这个时候不能手动来修改每一个变动的路径,太耗时,这个时候就要通过html-webpack-plugins这个插件来自动在html中生成对js的引用

webpack.config.js中加入plugins配置项

var htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: {
        main: './src/script/main.js',
        a: './src/script/a.js'
    },
    output: {
        path: './dist',
        filename: 'js/[name]-[hash].js'
    },
    plugins: [
        new htmlWebpackPlugin({
            template:'index.html',
            inject:'head'
        })
    ]
}

htmlWebpackPlugin插件中配置项template用来定义引用的模板文件,inject用来指定脚本在dom文档中的插入位置

  • 3-2自动化生成项目中的html文件(中)

template应用场景
在参数中传参,在模板中引用

plugins: [
    new htmlWebpackPlugin({
        template:'index.html',
        inject:'head',
        filename:'index-[hash].html',
        title:'webpack is good'//传参
        date:new Date()//传参
    })
]

在html的title中,以如下的方式引用

<title><%= htmlWebpackPlugin.options.title %></title>

<%= htmlWebpackPlugin.options.title %>这种方式的引用在模板中的任何一个位置都可以,例如

plugins: [
    new htmlWebpackPlugin({
        template:'index.html',
        inject:'head',
        title:'webpack is good'
        date:new Date()
    })
]
<body>
    <%= htmlWebpackPlugin.options.date %>
</body>

这样在编译后的index.html文件中会包含日期信息Tue Apr 04 2017 23:25:58 GMT+0800 (中国标准时间)

在html文件中body标签中,输入如下代码,运行 npm run webpack

    <% for(var key in htmlWebpackPlugin){ %>
    <%= key %>
    <% } %>

生成的文件中会有files options,这两个值说明在htmlWebpackPlugin插件中存在这两个对象

继续遍历htmlWebpackPlugin.files htmlWebpackPlugin.options这两个对象

    <% for(var key in htmlWebpackPlugin.files){ %>
    <%= key %>:<%= JSON.stringify(htmlWebpackPlugin.files[key])%>
    <% } %>
    <% for(var key in htmlWebpackPlugin.options){ %>
    <%= key %>:<%= JSON.stringify(htmlWebpackPlugin.options[key])%>
    <% } %>

得到

    //files
    publicPath:""
    chunks:{"main":{"size":27,"entry":"js/main-c6074c5f07c44041cf45.js","hash":"ddd0a31267a8793ca2d8","css":[]},"a":{"size":14,"entry":"js/a-c6074c5f07c44041cf45.js","hash":"ef609b383ce569e49d38","css":[]}}
    js:["js/main-c6074c5f07c44041cf45.js","js/a-c6074c5f07c44041cf45.js"]
    css:[]
    manifest:
    //options
    template:"F:\\localhost\\wamp\\www\\webpack-demo\\node_modules\\._html-webpack-plugin@2.28.0@html-webpack-plugin\\lib\\loader.js!F:\\localhost\\wamp\\www\\webpack-demo\\index.html"
    filename:"index.html"    
    hash:false   
    inject:"head"    
    compile:true    
    favicon:false    
    minify:false    
    cache:true   
    showErrors:true   
    chunks:"all"   
    excludeChunks:[]   
    title:"webpack is good"  
    xhtml:false
    date:"2017-04-04T15:45:55.712Z"
//压缩
minify:{
    removeComments:true,//删除注释
    collapseWhitespace:true//删除空格
}

可以用<%= %>这种灵活的方式实现更多的个性化定制

  • 3-3自动化生成项目中的html文件(下)

多文件形式/多页面应用

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'
    },
    output: {
        path: './dist',
        filename: 'js/[name]-[hash].js'
    },
    plugins: [
        new htmlWebpackPlugin({
            filename:'main.html',
            template: 'index.html',
            title: 'webpack is main',
            date: new Date()
        }),
        new htmlWebpackPlugin({
            filename:'a.html',
            template: 'index.html',
            title: 'webpack is a',
            date: new Date()
        }),
        new htmlWebpackPlugin({
            filename:'b.html',
            template: 'index.html',
            title: 'webpack is b',
            date: new Date()
        }),
        new htmlWebpackPlugin({
            filename:'c.html',
            template: 'index.html',
            title: 'webpack is c',
            date: new Date()
        })
    ]
}

chunks用来指定匹配的生成文件中应该生成数组中的文件(excludeChunks和chunks相反)

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'
    },
    output: {
        path: './dist',
        filename: 'js/[name]-[hash].js'
    },
    plugins: [
        new htmlWebpackPlugin({
            filename:'main.html',
            template: 'index.html',
            title: 'webpack is main',
            date: new Date(),
            chunks:['a','b','c']
        }),
        new htmlWebpackPlugin({
            filename:'a.html',
            template: 'index.html',
            title: 'webpack is a',
            date: new Date(),
            chunks:['b','c']
        }),
        new htmlWebpackPlugin({
            filename:'b.html',
            template: 'index.html',
            title: 'webpack is b',
            date: new Date(),
            chunks:['a','c']
        }),
        new htmlWebpackPlugin({
            filename:'c.html',
            template: 'index.html',
            title: 'webpack is c',
            date: new Date(),
            chunks:['a','b']
        })
    ]
}

main.html中会生成 a.js b.js c.js
a.html中会生成b.js c.js
b.html中会生成a.js c.js
c.html中会生成a.js b.js

将生成的脚本变成内联脚本

compilation.assets[htmlWebpackPlugin.files.chunks.main.entry].source()

如果在申明publicPath的情况下代码应该是这样

compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source()

htmlWebpackPlugin.files.publicPath.length 得到publicPath的长度例如 https://www.baidu.com
htmlWebpackPlugin.files.chunks.main.entry.substr()得到文件真实路径
最后用compilation.assets[].source()得到内容
main.js已经以内联的方式插入到文档,那么多后续的出来main.js则不需要任何操作,可以在index.html里面写入这样的模板语法,来判断是否是main.js以外的文件,如果不是则插入

四、处理项目中的资源文件

  • 4-1什么是loader以及loader的特性

加载器是应用于模块源代码的转换。它们允许您在导入或“加载”它们时预处理文件。因此,加载器就像是其他构建工具中的“任务”,并提供了一种强大的方法来处理前端构建步骤。加载器可以将文件从不同的语言(如打字稿)转换为JavaScript,或者将内联图像转换为数据url。加载器甚至允许您直接从JavaScript模块导入CSS文件

有3种使用loader的方式
1. 在webpack.config.js文件中指定

module: {
    rules: [{
        test: /\.css$/,
        use: [{
            loader: 'style-loader'
        },
        {
            loader: 'css-loader',
            options: {
                modules: true
            }
        }]
    },
    {
        test: /\.jsx?$/,
        include: [path.resolve(__dirname, "app")],
        exclude: [path.resolve(__dirname, "app/demo-files")],
        issuer: {
            test,
            include,
            exclude
        },
        enforce: "pre",
        enforce: "post",
        loader: "babel-loader",
        options: {
            presets: ["es2015"]
        },
    },
    {
        test: /\.html$/,
        use: [
        // apply multiple loaders and options
        "htmllint-loader", {
            loader: "html-loader",
            options: {}
        }]
    },
    ]
}
  1. 在每个import语句中显式地指定它们
    require('style-loader!css-loader!./style.css')
    import Styles from 'style-loader!css-loader?modules!./styles.css'
  2. 在命令行中使用
    webpack --module-bind 'css=style-loader!css-loader'
    webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

    • 4-2使用babel-loader转换ES6代码

npm install –save-dev babel-loader babel-core babel-preset-env

cnpm install --save-dev babel-loader babel-core babel-preset-es2015
cnpm install babel-preset-env --save-dev

webpack-demo
-dist
-node_modules
-src
--components
---layer
----layer.html
----layer.js
----layer.css
--app.js
-index.html
-package.json
-webpack.config.js
const htmlWebpackPlugin=require('html-webpack-plugin');
const path = require('path');
module.exports={
    entry:'./src/app.js',
    output:{
        path:__dirname+'/dist',
        filename:'[name].bundle.js'
    },
    module:{
        rules:[
            {
                test:/\.js$/,
                include:path.resolve(__dirname, "src"),
                exclude: path.resolve(__dirname, "node_modules"),
                use:{
                    loader: "babel-loader",
                    options:{
                        "presets": [
                          "es2015"
                        ]
                    }
                }

            }
        ]
    },
    plugins:[
        new htmlWebpackPlugin({
            title:'app',
            inject:'head',
            template:'index.html',
            filename:'index.html',
            minify:{
                collapseWhitespace:true
            }
        })
    ]
}

presets:['latest']也可以放在package.json文件中

"babel":{
      "presets": [
        "es2015"
      ]
}

或者放在.babelrc

{
  "presets": [
    "es2015"
  ]
}

注意,webpack目前只在您的node_modules文件夹中搜索加载器。如果这些加载器是在您的node_modules文件夹之外定义的,那么您需要使用resolveLoader属性来获得webpack来包含您的loader。例如,假设您的自定义加载器包含在一个名为loaders的文件夹中。您需要在配置文件中添加以下内容:

resolveLoader: {
    modules: ['node_modules', path.resolve(__dirname, 'loaders')]
}

path.resolve(__dirname+''),用来将相对路径改为绝对路径
cnpm install --save-dev babel-preset-latest
cnpm install --save-dev babel

注意:在webpack2.0中 有些不一样

module: {
    rules: [
        {
            test:  /\.js$/,
            use: 'babel-loader',
            exclude:  path.resolve(__dirname + 'node_modules'),
            include: path.resolve(__dirname + 'src'),
            query: {
                presets: ['env']
            }
        }
    ]
}

注意:加入include配置项会导致babel不处理es6语法,原因暂不明

  • 4-3处理项目中的css
    postcss-loader
    autoprefixer是postcss-loader的一个子集
    postcss用在css-loaderstyle-loader之后,用在sass|less|stylus-loader之前
module: {
    rules: [{
            test:/\.js$/,
            include:__include,
            exclude: __exclude,
            use:{
                loader: "babel-loader",
                options:{
                    "presets": [
                      "es2015"
                    ]
                }
            }
        },
        {
            test: /\.css$/,
            use: [
                'style-loader',
                {loader:'css-loader', options: {importLoaders: 1}},
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function() {
                            return [
                                require('autoprefixer')
                            ];
                        }
                    }
                }
            ]
        }
    ]
}

注意:
1. loader的执行顺序从右向左
2. style-loader!css-loader?importLoaders=1!postcss-loader
3. ?importLoaders=1css-loader后面的参数,意思是在css-loader后指定一个处理import样式的命令

  • 4-4使用less和sass

sass-loader less-loader

npm install sass-loader node-sass webpack --save-dev

sass-loader依赖node-sasswebpack

{
    test:/\.scss$/,
    use:[
        'style-loader',
        {loader:'css-loader', options: {importLoaders: 1}},
        {
            loader:'sass-loader'
        },
        {
            loader: 'postcss-loader',
            options: {
                plugins: function() {
                    return [
                        require('autoprefixer')
                    ];
                }
            }
        }
    ]
}
  • 4-5处理模板文件
    html-loader
{
    test:/\.html$/,
    loader:'html-loader'
}

ejs-loader

{
    test:/\.tpl$/,
    loader:'ejs-loader'
}
  • 4-6处理图片及其他文件
    file-loader url-loader用来处理图片
    url-loaderfileloader差不多,但是可以指定limit参数,当图片大小,小于limit时由url-loader处理成base64,当图片大小大于imit时就由file-loader处理成路径

image-webpack-loader用来压缩图片

在模版中使用相对路径图片的方法

${require('../../assets/bg.png')}
var htmlWebpackPlugin = require('html-webpack-plugin');

var path = require('path');
module.exports = {
    entry: {
        "main": __dirname + '/src/script/main.js',
        "a": __dirname + '/src/script/a.js',
        "b": __dirname + '/src/script/b.js',
        "c": __dirname + '/src/script/c.js',
    },
    output: {
        filename: 'js/[name]-[hash].js',
        path: __dirname + '/dist',
    },
    module: {
        rules: [{
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: path.resolve(__dirname + 'node_modules'),
                query: {
                    presets: ['env']
                }
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader:'css-loader',
                        options:{
                           importLoaders:1
                         }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: function() {
                                return [
                                    require('autoprefixer')
                                ];
                            }
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new htmlWebpackPlugin({
            filename: 'main.html',
            template: 'index.html',
            inject: false,
            title: 'webpack is main.html',
            date: new Date(),
            excludeChunks: ['a', 'b']
        }),
        new htmlWebpackPlugin({
            filename: 'a.html',
            template: 'index.html',
            inject: false,
            title: 'webpack is a.html',
            date: new Date(),
            excludeChunks: ['b', 'c']
        }),
        new htmlWebpackPlugin({
            filename: 'b.html',
            template: 'index.html',
            inject: false,
            title: 'webpack is b.html',
            date: new Date(),
            excludeChunks: ['a', 'c']
        }),
        new htmlWebpackPlugin({
            filename: 'c.html',
            template: 'index.html',
            inject: false,
            title: 'webpack is c.html',
            date: new Date(),
            excludeChunks: ['a', 'b']
        })
    ]
}
const htmlWebpackPlugin=require('html-webpack-plugin');
const path = require('path');
const __include=path.resolve(__dirname, "src");
const __exclude=path.resolve(__dirname, "node_modules");
module.exports={
    entry:'./src/app.js',
    output:{
        path:__dirname+'/dist',
        filename:'[name].bundle.js'
    },
    module:{
        rules:[
            {
                test:/\.js$/,
                include:__include,
                exclude: __exclude,
                use:{
                    loader: "babel-loader",
                    options:{
                        "presets": [
                          "es2015"
                        ]
                    }
                }
            },
            {
                test:/\.html$/,
                loader:'html-loader'
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {loader:'css-loader', options: {importLoaders: 1}},
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: function() {
                                return [
                                    require('autoprefixer')
                                ];
                            }
                        }
                    }
                ]
            },
            {
                test:/\.scss$/,
                use:[
                    'style-loader',
                    {loader:'css-loader', options: {importLoaders: 1}},
                    {
                        loader:'sass-loader'
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: function() {
                                return [
                                    require('autoprefixer')
                                ];
                            }
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new htmlWebpackPlugin({
            title:'app',
            inject:'body',
            template:'index.html',
            filename:'index.html',
            minify:{
                collapseWhitespace:true
            }
        })
    ]
}

webpack3.x.x-demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值