[转载] Webpack 入门 --- Part III

https://segmentfault.com/a/1190000006178770

插件(Plugins)

插件(Plugins)是用来拓展webpack功能的,它们会在整个构建过程中生效,执行相关的任务。
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less...),一次处理一个; 插件并不直接操作单个文件,它直接对整个构建过程起作用。
webpack有很多内置插件,同时也有很多第三方插件,可以让我们完成更加丰富的功能。

使用插件的方法

要使用某个插件,我们需要通过npm安装它,然后要做的事情就是在webpack配置中的plugins关键字部分添加该插件的一个实例(plugins是一个数据)继续上面的例子,我们添加了一个给打包后代码添加版权声明的插件。

const webpack = require('webpack');

module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            }, {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('Copyright forfan06')
    ]
}

通过这个插件,打包后的JS文件会有copyright版权声明。
这就是webpack插件的基础用法了, 下面是几个常用的插件:

HtmlWebpackPlugin

这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的js文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。

安装

npm install --save-dev html-webpack-plugin

这个插件自动完成了我们之前手动做的一些事情,在正式使用之前需要对一直依赖的项目结构做一些更改:

  1. 移除public文件夹,利用此插件,index.html文件会自动生成,此外css已经通过前面的操作打包到js中了。
  2. 在src目录下,创建一个index.tmpl.html文件模板,这个模板包含title等必须元素,在编译过程中,插件会依据此模板生成最终的html页面,会自动添加所依赖的css,js,favicon等文件。

index.tmpl.html中的模板源代码如下:



    
        
        Webpack Sample Project
    
    
        

3. 更新webpack的配置文件,方法同上,新建一个build文件夹用来存放最终的输出文件
 

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

module.exports = {
    entry: __dirname + '/src/main.js',     // 唯一入口文件
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: './public', // 本地服务器所加载的页面所在的目录
        historyApiFallback: true,   // 不跳转
        inline: true      // 实时刷新
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: 'babel-loader'
                },
                exclude: /node_modules/
            }, {
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader'
                    }, {
                        loader: 'css-loader',
                        option: {
                            modules: true
                        }
                    }, {
                        loader: 'postcss-loader'
                    },
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('Copyright test'),
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.tmpl.html'   // new 一个这个插件的实例,并传入相关的参数
        })
    ]
}

再次执行npm start你会发现,build文件夹下面生成了bundle.js和index.html。

Hot Module Replacement

Hot Module Replacement(HMR)也是webpack里很有用的一个插件,它允许你在修改组件代码后,自动刷新,实时预览修改后的效果。
在webpack中实现HMR也很简单,只需要做两项配置:
     1. 在webpack配置文件中添加HMR插件;
     2. 在Webpack Dev Server中添加‘hot’参数;
不过配置完这些后,js模块其实还是不能自动热加载的,还需要再你的js模块中执行一个webpack提供的API才能实现热加载,虽然这个API不难使用,但是如果是React模块,使用我们已经熟悉的Babel可以更加方便的实现功能热加载。
整理下思路,具体实现方法如下:
   1. babel和webpack是独立的工具,
   2. 二者可以一起工作,
   3. 二者都可以通过插件拓展功能,
   4. HMR是一个webpack插件,它让你能实现实时观察模块修改后的效果。但是如果你想让它工作,需要对模块进行额外的配置,
   5. Babel有一个佳作react-transform-hmr的插件,可以在不对React模块进行额外配置的前提下让HMR正常工作;
通过配置上例来看如何实现热加载

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

module.exports = {
    entry: __dirname + '/src/main.js',     // 入口文件
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: './public',    // 本地服务器加载页面所在的目录
        historyApiFallback: true,   // 不跳转
        inline: true,
        hot: ture
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: 'babel-loader'
                },
                exclude: /node_modules/
            },{
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader'
                    },{
                        loader: 'css-loader',
                        options: {
                            modules: true
                        }
                    },{
                        loader: 'postcss-loader'
                    }
                ]
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('Copyright test'),
        new HtmlWebpackPlugin({
            template: __dirname + './src/index.tmpl.html'   // new一个插件的实例,并传入相关的参数
        }),
        new webpack.HotModuleReplacementPlugin()    // 热加载插件
    ]
}

安装react-transform-hmr

npm install --save-dev babel-plugin-react-transform react-transform-hmr

配置babel, you can refer this to https://www.npmjs.com/package/react-transform-hmr

// .babelrc
{
    "presets": [ "react", "env" ],
    "env": {
        // only enable it when process.env.NODE_ENV is 'development' or undefined
        "development": {
            "plugins": [[ "react-transform", {
                "transform" [{
                    "transform": "react-transform-hmr",
                    // if you use React Native, pass "react-native" instead:
                    "imports": [ "react" ],
                    // this is important for Webpack HMR:
                    "locals": [ "module" ]
                }]
                // note: you can put more transfor into array
                // this is just one of them!
            }]]
        }
    }
}

现在当你使用React时,可以预加载模块了,每次保存就可以在浏览器上看到实时的更新。

产品阶段的构建

目前为止,我们已经使用webpack构建了一个完整的开发环境!!!但是在产品阶段,可能还u要对打包的文件进行额外的处理,比如说优化、压缩、缓存以及分离css和js。
对于复杂的项目来说,需要复杂的配置,这时候分解配置文件为多个小的文件可以使得事情井井有条,以上面的例子来说,我们创建一个webpack.production.config.js的文件,在里面加上借本的配置,它和元素的webpack.config.js很像,如下:

// webpack.production.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('hmlt-webpack-plugin');

module.exports = {
    entry: __dirname + '/src/main.js',   // 入口文件
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: './public',   //本地服务器加载页面所在的目录
        historyApiFallback: true,  // 不跳转
        inline: true   // 实时刷新
        hot: true
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: 'babel-loader'
                },
                exclude: /node_modules/
            },{
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [{
                        loader: 'css-loader',
                        options: {
                            modules: true
                        }
                    }, {
                        loader: 'postcss-loader'            
                    }]
                })
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin('Copyright test'),
        new HtmlWebpackPlugin({
            template: __dirname + '/src/index.tmpl.html'  // new一个插件的实例,并传入相关参数
        }),
        new webpack.HotModuleReplacementPlugin()  // 热加载插件                    
    ]
}
// package.json
{
    "name": "test",
    "version": "1.0.0",
    "description": "This is a test for webpack",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "webpack",
        "server": "webpack-dev-server --open",
        "build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"
    },
    "author": "forfan06",
    "license": "ISC",
    "devDependencies": {
        // ...
    },
    "dependencies": {
        // ...
        "react": "^15.6.1",
        "react-dom": "^15.6.1"
    }
}

注意如果是window电脑,build需要配置为

"build": "set NODE_ENV=production && webpack --config ./webpack.production.config.js --progress"

优化插件

webpack提供了一些在发布阶段非常有用的插件,它们大多来自于webpack社区,可以通过npm安装,通过以下插件可以完成铲平发布阶段所需的功能:
   1. OccurenceOrderPlugin: 为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID
   2. UglifyJsPlugin: 压缩js代码
   3. E下tractTextPlugin:分离css和js文件
其中,OccurenceOrder和UglifyJS plugins都是内置插件,你需要做的只是安装其他非内置插件
          npm install --save-dev extract-text-webpack-plugin
在配置文件的plugins后引用它们

// webpack.production.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: __dirname + '/src/main.js',   // 入口文件
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devtool: 'eval-source-map',
    devServer: {
        contentBase: './public',
        historyApiFallback: true,
        inline: true,
        hot: true
    },
    module: {
        rules: [
            {
                test:/(\.jsx|\.js)$/,
                use: {
                    loader: 'babel-loader'
                },
                exclude: /node_modules/
            },{
                test: /.css$/,
                use: [
                    {
                        loader: 'style-loader'
                    }, {
                        loader: 'css-loader',
                        options: {
                            modules: true
                        }
                    }, {
                        loader: 'postcss-loader'
                    }
                ]
            }
        ]
    },
    plugins: []
}

此时,执行npm run build可以看见代码是被压缩的。

缓存

缓存无处不在,使用缓存的最好方法是保证你的文件名和文件内容是匹配的(内容改变,名称相应的跟着改变)
webpack可以把一个哈希值添加到打包的文件名中,使用方法如下,添加特殊的字符串混合体([name], [id] and [hash])到输出文件名前:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    // ...
    output: {
        path: __dirname + '/build',
        filename: 'bundles-[hash].js'            
    },
    // ...
}

去除build文件中的残余文件

添加了hash之后,会导致改变文件内容重新打包时,文件名不同而内容越来越多,因此这里需要使用到另外一个插件: clean-webpack-plugin。
安装:

npm install clean-webpack-plugin --save-dev

使用:

const CleanWebpackPlugin = require('clean-webpack-plugin');


module.exports = {
    {
        // ...
    },
    plugins: [
        // ... other plugins
        new CleanWebpackPlugin('build/*.*', {
            root: __dirname,
            verbose: true,
            dry: false
        })
    ]
}

引入clean-webpack-plugin插件后在配置文件的plugins中做对应配置即可。
关于clean-webpack-plugin的详细使用可参考 https://github.com/johnagan/clean-webpack-plugin

你可能感兴趣的:(前端之路)