用一个hello world项目学习webpack

631 阅读4分钟
原文链接: imjianjian.gitee.io

项目准备

项目地址

项目结构

- src
    - app
        - App.vue
    - img
        - logo.png
    - style
        - app.scss
    - index.html
    - main.js

webpack基本概念

entry

即webpack打包的入口js文件,可以根据项目实际情况配置成但入口或者多入口,webpack会根据入口文件内的引入的文件绘制依赖图,将该模块和模块对应的依赖都打包到一个文件中。

//单入口
const config = {
    entry:'a.js'
}
//多入口
const config = {
    entry:{
        a:'a.js',
        b:['b1.js','b2.js']  //多个文件打包为一个文件
    }
}

output

即webpack打包后的输出,即使此时的entry中存在多个入口,也只提供单一的输出配置。

//单一入口情况,一下将所有文件都打包到dist/bundle.js里
const config = {
    output:{
        filename:'bundle.js',
        path:path.join(__dirname,'dist')
    }
}
//多入口情况
const config ={
    output:{
        filename:'[name].js',
        path:path.join(__dirname,'dist')
    }
}
这里的输出文件名中可以使用[name],[hash],[chunkhash]等占位,这样输出的文件名中就有带有资源hash值。[hash]是本次打包所有资源的hash值,同义词打包的文件得到的hash是一样的,而[chunkhash]是单个文件打包的hash值,每个文件且每次打包都不相同。还可以使用[hash:8]来取hash值得位数

Loader

webpack是一个js bundler,如果需要它对非js得模块,例如typeScript,sass,less,vue等模块进行打包,则需要对应的loader进行转换。而且同一种资源有时需要使用不止一种loader。

const config ={
    module:{
        rules:[
            {
                test: /\.vue$/, 
                use: [{loader: 'vue-loader'}]
            },
            {
                test:/\.scss/,
                use:[
                    {loader:'style-loader'},
                    {
                        loader:'css-loader',
                            options: {
                                modules: true
                            }
                    },
                    {loader:'sass-loader'}
                ]
            }
        ]
    }
}

在rules数组中的每一项都是一种模块类型的转换规则,test参数匹配对应后缀的文件,use数组中配置对应使用的loader以及配置loader的其他参数。

官方推荐的loader

Plugins

plugins用于解决其他loader无法做到的事情,比如压缩资源,启动开发服务器等等。

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

const config ={
    plugins:[
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({
            template:path.join(__dirname,'src/index.html')
        })
    ]
}

plugins数组的每一项就是一个插件

webpack自带的以及推荐使用的Plugins

webpack配置文件结构

webpack默认的配置文件名为webpack.config.js,当然也可以自定义其他文件名,只要在webpack –config filename命令中修改filename为当前的配置文件即可。

完整的webpack配置参数可以查看官方文档

开发模式和打包模式(Dev&Build)

可以通过命令行向webpack闯入参数,以判断使用开发模式还是打包。

在package.json中配置npm script:

"scripts": {
  "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
  "dev": "cross-env NODE_ENV=develement webpack-dev-server --config webpack.config.js"
}

命令行中使用了cross-env用于跨平台地设置及使用环境变量,具体的参照官方github说明

在build和dev中我们分别向webpack传入了不同的NODE_ENV参数值。在webpacl配置文件中,可以使用process.env.NODE_ENV来的到这个值,以便判断该运行那哪个模式。

webpack-dev-server

在webpack中用devServer参数来配置它,在此之前我们需要先判断是否运行在开发模式

var WebpackDevServer = require('webpack-dev-server');

//获得NODE_ENV参数,用于判断处于开发模式还是打包模式
var isDev = process.env.NODE_ENV === 'develement';

const config = {
    ....
}

if(isDev){
    //webpack-dev-server不能使用chunkhash,否则会报错
    config.output.filename ='[name]-[hash].js';
    config.devtool = '#cheap-module-eval-source-map';

    config.plugins.push(
        new webpack.HotModuleReplacementPlugin(), //热更新插件
        new webpack.NoEmitOnErrorsPlugin() //防止错误信息导致webpack退出
    )

    //启动开发服务器
    config.devServer={
        contentBase:path.join(__dirname,'dist'),
        compress:true, //启用gzip压缩
        port:8080,
        hot:true, //启用webpack热模块替换特性
        open:true //是否在开始服务器后打开浏览器
    }
}

在devServer中配置hot:true并不在代表已经启用了热模块替换,还需要使用webpack.HotModuleReplacementPlugin插件才能生效,hot仅仅是一个开关

单独打包css文件

想vue文件中的样式通常会被打包进js文件中,在该组件被加载时同时加载样式。而有一些公共的样式通常会写在单独的文件中,如果我们在多个组件中引用公共样式,那么公共样式会在多个js模块中被打包,这样会增加文件的体积。这是应该将这些公共样式提取出来单独打包。

这里我们使用extract-text-webpack-plugin插件来提取公共样式,所以此时我们的配置文件中就该改为这样:

var ExtracTextPlugin = require('extract-text-webpack-plugin');

const config ={
    module:{
        rules:[
            {
                test: /\.scss/,
                use: ExtracTextPlugin.extract({
                    use: [{
                        loader: 'css-loader'
                    }, {
                        loader: 'sass-loader'
                    }]
                })
            }
        ]
    },
    plugins:[
         new ExtracTextPlugin('style-[contentHash:8].css')
    ]
}

这样就能将scss文件单独打包了

提取公共模块

同理我们在项目中使用类库,也需要单独打包,以防止重复加载,节省流量。

这里使用的是webpack自带的插件CommonsChunkPlugin,在entry中添加vendor模块,然后在插件中配置单独打包vue。

var config = {
    entry: {
        app:path.join(__dirname, 'src/main.js'), 
        vendor:['vue']
    },
    plugins:[
        new webpack.optimize.CommonsChunkPlugin({
            name:'vendor'
        })
    ]
}