6

webpack(v3.*)

1、webpack介绍

webpack官网:https://webpack.js.org/
webpack中文官网:https://doc.webpack-china.org...
webpack打包工具源代码:https://github.com/webpack/we...

2、初始化项目

cd yourproject
npm init       //生成package.json文件
npm install webpack --save-dev   

3、webpack.config.js配置文件

(1)、context:上下文,这里省略了,默认为当前文件模块的绝对路径,下面的entry和output中的路径都是相对于context上下文的相对路径.

(2)、output属性:(v3.10.0版本要求path是绝对路径,需要使用node.js的path模块)

注意: path.resolve方法用于将相对路径转为绝对路径。

var path = require("path");  //使用前引入path模块
module.exports = {
    entry: './src/js/main.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist/js'),
        publicPath: "https://cdn.example.com/"  //用publicPath配置打包后生成线上地址
    }
}

注意: publicPath,当我们需要上线的时候设置此属性,最后打包的文件路径会被替换为publicPath设置的地址值。

注意: filename: '[name]-[chunkhash].js',filename使用占位符确保每个文件具有唯一的名称。同时使用chunkhash可以达到控制文件版本号的作用,这点与gulp是相通的原理。所以,一旦文件做了修改,再执行webpack,则更改过的文件的chunkhash会发生改变,未做改动的文件的chunkhash不变。

(3)、plugins属性

介绍:plugins 是一个数组,里面是实例化的plugin,即new HtmlWepackPlugin({//code}),这种形式。

① html-webpack-plugin插件:该插件用于生成一个HTML5文件,这个文件用script标签引用所有webpack包。(https://www.npmjs.com,npm官网...

//安装
npm install html-webpack-plugin --save-dev

//webpack.config.js配置文件中引入
var HtmlWepackPlugin = require("html-webpack-plugin");

//设置配置项
plugins: [
    new HtmlWepackPlugin({
        filename:'index-[hash].html',  //输出文件名称
        template:'index.html',   //模板路径
        inject:"head",     //值:body,head,false;script和link文件注入body或head中,或者false不注入。
        chunks:["index","common"],      //允许插入到模板中的一些chunk,不配置此项默认会将entry中所有的chunk注入到模板中。多页应用配置多个页面时,每个页面注入的thunk应该是不相同的,需要通过该配置为不同页面注入不同的thunk.
        excludeChunks: ["constan"],     //这个与chunks配置项正好相反,用来配置不允许注入的thunk。
        showErrors: true,     //值:true/false,默认true;是否将错误信息输出到html页面中。这个很有用,在生成html文件的过程中有错误信息,输出到页面就能看到错误相关信息便于调试。
        title:"MyApp",   //需要在引用template模板中调用此变量
        minify: {  //压缩代码
            collapseWhitespace: true,   //删除空格
            html5: true
        }
    })
]

注意: title属性的坑:var HtmlWebpackPlugin = require('html-webpack-plugin'); 这个变量随意。但是在模板中<title><%= htmlWebpackPlugin.options.title %></title>必须使用驼峰式命令。不然会报错一直提示这个插件未定义。

注意: 在页面中引入inline的script方法如下:

在github上,https://github.com/jantimon/h...。共用的main.js以inline的形式引进,a.js,b.js,c.js以外链的形式引进.模板index.html中,

首先在<head>中

    <script type="text/javascript">
        <%= compilation.assets[htmlWebpackPlugin.files.chunks.main.entry.substr(htmlWebpackPlugin.files.publicPath.length)].source() %>
    </script>

重点:!!!compilation.assets是webpack暴露出来可以获取文件数据的方法。通过传文件名路径进这个对象,拿到这个文件的索引,通过调用source拿到文件内容。
compilation.assets需要的是不带publicPath,htmlWebpackPlugin.files.chunks.main.entry带publicPatch,所以用substr()截取。

然后在<body>中:

    <%= htmlWebpackPlugin.files.chunks[k].entry %>

最后在webpack.config.js中: inject属性设置为false即可。

(4)、loader属性(以babel-loader为例,用babel-loader将js文件转义为浏览器可识别的js)

module:{         
    rules:[    //模块规则
        {
            test: /\.js$/,    //正则匹配
            use: [{   
                loader:'babel-loader',
                options:{
                    presets: ["env"] //采用babel-loader的"env"规则将找的es6,es7,es5语法转码为浏览器可识别的js
                }
            }],
            include: [
             path.resolve(__dirname, "/src")   //指定babel-loaders寻找的文件路径,注意需是绝对路径
            ],
            exclude: [
             path.resolve(__dirname, "/node_modules/")   //排除node_modules文件下js,注意需是绝对路径
            ]
        }
    ]
},

注意: webpack官网介绍到:“Rule.loader is a shortcut to Rule.use: [ { loader } ]”. 即下图:

图片描述

(5)、loader属性(css处理的loader)(postcss参考文章:https://segmentfault.com/a/11...

在web开发中浏览器兼容问题,我们不得不使用兼容性前缀,less语言在编译时可以补全css代码的兼容性前缀,但是针对css文件不全前缀需要使用postcss-loader。如下图:

图片描述

在common.css中引入其他的css文件:
图片描述

在app.js入口文件中引入common.css,这样打包的时候就能将css文件进行打包:
图片描述

(6)、wbpack-dev-server

//首先安装插件
npm i webpack-dev-server  --save-dev
npm i cross-env  --save-dev
npm i html-webpack-plugin  --save-dev

package.json文件:

"scripts":{
    //prod环境
    "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
    //dev环境
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
  }

webpack.config.js文件:

const path = require("path")  
const HTMLWebapckPlugin = require("html-webpack-plugin")
const webpack = require('webpack')  //引入webpack 

//在package.json中的“NODE_ENV=development”,可通过下面的process.env读到变量NODE_ENV
const isDev = process.env.NODE_ENV === "development"


const config = {

    target:"web",//web平台

    entry: path.join(__dirname,'src/index.js'),
    output:{
        filename:'bundle.js',
        path:path.join(__dirname,"dist")

    },
    module:{
        rules:[
            {
                test:/\.vue$/,
                loader:'vue-loader'
            },
            {
                test:/\.css$/,
                use:[
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test:/\.(gif|jpg|jpeg|png|svg)$/,
                use:[
                    {
                        loader:'url-loader',
                        options:{
                            limit:1024,
                            name:'[name]-[hash].[ext]'
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        //使用Vue、react框架时需要DefinePlugin这的插件,因为框架会根据不同环境打包依赖,所以要区分环境从而选择不同的依赖
        new webpack.DefinePlugin({
            //定义环境变量,对应上面的isDev判断
            'process.env':{
                NODE_ENV:isDev ? '"development"' : '"production"' //注意此处单引号内还需要双引号
            }
        }),
        //生成HTML页面
        new HTMLWebapckPlugin()
    ]
}

//dev环境
if(isDev){
    //通过devtool对代码进行映射,可以在浏览器端可以调试
    config.devtool = "#cheap-module-eval-sourve-map"
    //devserver 是在webpack2以后才出现的
    config.devServer = {
        port:'8020', //端口号
        host:"0.0.0.0", //设置成这样后,移动端也可以通IP访问页面
        //webpack编译时任何错误显示在浏览器中
        overlay:{
            errors:true,
        },
        open:true,//自动打开浏览器
        hot:true //webpack功能:不再重新刷新整个页面,而是局部更新,即热更新
    }
    config.plugins.push(
        new webpack.HotModuleReplacementPlugin(),  //搭配hot:true一起使用
        new webpack.NoEmitOnErrorsPlugin()  //搭配hot:true一起使用,去除一些不需要展示的信息
    )
}


module.exports = config

执行npm run dev 就可以通过localhost:8020打开页面

(7)、webpack单独打包css文件

//安装依赖
npm i extract-text-webpack-plugin

在webpack.config.js文件中引用:(结合6中的配置文件)

//dev环境
if(isDev){
    config.module.rules.push(
        {
            test:/\.scss$/,
            use:[
                'style-loader',
                'css-loader',
                {
                    loader:'postcss-loader',
                    options:{
                        sourceMap:true
                    }
                },
                'sass-loader'

            ]
        }
    )
    config.devtool = "#cheap-module-eval-sourve-map"
    //devserver 是在webpack2以后才出现的
    config.devServer = {
        port:'8020', //端口号
        host:"0.0.0.0", //设置成这样后,移动端也可以通IP访问页面
        //webpack编译时任何错误显示在浏览器中
        overlay:{
            errors:true,
        },
        open:true,//自动打开浏览器
        hot:true //热更新
    }
    config.plugins.push(
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
    )
}else{
//正式环境
    config.output.filename='[name].[chunkhash:8].js'  //正式环境使用chunkhash,dev环境不能使用chunkhash,可使用hash.
    config.module.rules.push({
        test:/\.scss$/,
        use:ExtractTextWebpack.extract({
            fallback:'style-loader',
            use:[
                'css-loader',
                {
                    loader:'postcss-loader',
                    options:{
                        sourceMap:true
                    }
                },
                'sass-loader'
            ]
        })
    })
    config.plugins.push(
        new ExtractTextWebpack('style.[contentHash:8].css')
    )
}
注意:vue组件中的css样式是不会打包到上面的style.[contentHash:8].css文件中的,因为他是异步加载的。

(8)、单独打包类库文件及hash

将类库代码和业务代码分离打包,利用浏览器长期的缓存类库代码。
//正式环境配置
 {
    config.entry = {
    //业务逻辑代码
   app:path.join(__dirname,"src/index.js"),
   //类库代码在此声明,此处以Vue框架为例
    vendor: ['vue']
    }
    config.output.filename='[name].[chunkhash:8].js',
    config.module.rules.push({
    test:/\.scss$/,
    use:ExtractTextWebpack.extract({
    fallback:'style-loader',
    use:[
        'css-loader',
        {
            loader:'postcss-loader',
            options:{
                sourceMap:true
            }
        },
        'sass-loader'
    ]
    })
    }),
    config.plugins.push(
    new ExtractTextWebpack('style.[contentHash:8].css'),
    //单独打包,app中就不会出现类库代码,必须放在runtime之前
    new webpack.optimize.CommonsChunkPlugin({
    //name属性值要和上面定义的vendor一致
    name:'vendor'
    }),
    new webpack.optimize.commonsChunkPlugin({
    name:'runtime'
    })
    )
 }       
hash与chunkhash区别:
hash:打包的所有文件共用的一个值
chunkhash:打包的不同的块拥有不同的chunkhash,所以正式环境应使用chunkhash,这样可以保证类库文件不会再每次更改业务重新打包后,又拥有一个新的hash值,而是一直使用之前的chunkhash,这样浏览器就不会在去下载那些依赖,从而实现了缓存。

详细请见:https://www.imooc.com/article/21538

Miss_Ye
1.5k 声望157 粉丝

知识的价值不在于占有,而在于使用!