webpack 4.0使用指南

WebPack4.X 使用指南

一、简介:

webpack是一个前端自动化打包工具,根据它的名字也很好理解,web-pack顾名思义就是前端打包工具;它的使用是基于Node和NPM的,所以在安装使用webpack之前,需要安装nodejs,nodejs的版本过低也不行,所以推荐安装nodejs版本为v8.11.2以上,npm版本为v5.6.0以上;

如何查看node和npm版本?

答:安装完毕nodejs之后,在命令行输入node -v和npm -v查看。

二、项目建立:

第一步:新建一个文件夹,命名为wp。

第二步:在cmd命令行中使用cd命令切入到wp文件夹中,输入npm init或npm init -y,初始化package.json文件;需要注意的是如果package.json的name为webpack可能会引起错误,所以name尽量避免输入为webpack。

如图:

第三步:将wp文件夹拖入到sublime等编辑工具中,并在wp根目录下新建一个webpack.config.js的文件。

webpack.config.js里面应该配置的项目如下:

module.exports = {
    entry: '',               // 入口文件
    output: {},              // 出口文件
    module: {},              // 处理对应模块
    plugins: [],             // 对应的插件
    devServer: {},           // 开发服务器配置
    mode: 'development'      // 模式配置
}

我们先做一个默认配置:

const path = require('path');   
module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    }
}   

及将上述所谓的默认配置代码粘贴到webpack.config.js文件中

解释:
所谓的入口文件entry和出口文件output指的都是.js文件,当前的配置是单个入口文件和出口文件,后面我们在配置多页面的时候回有多入口和出口文件。

第四步:根据第三步中的配置内容需要注意到两个路径和文件:

 entry: './src/index.js',
 filename: 'bundle.js'
 path: path.resolve('dist')

'./src/index.js'的意思是在当前wp根目录下要新建一个src文件夹,里面,并且在里面新建一个index.js文件。

filename: 'bundle.js'和path: path.resolve('dist')的意思是最终打包完毕后会在wp根目录下自动创建一个叫dist的文件夹,里面包含一个bundle.js文件

打包前目录结构和代码:

第五步:接下来我们将根据第四步的内容进行打包,要想使用webpack打包,需要使用npm安装webpack 和 webpack-cli,在cmd命令行中输入:

npm install webpack webpack-cli --save-dev

如图:


安装完毕后修改package.json文件中的scripts,如下:

{
  "name": "wp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev" : "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2"
  }
}

然后在cmd命令行中输入npm run dev进行打包。

如下图:

打包后目录结构和代码:

其中增加了一个dist文件夹,里面增加了一个bundle.js文件;这就是之前我们说的输出文件。

第六步:在src目录下新建一个index.html文件,里面引入打包后的bundle.js文件作为测试。

运行后的结果如下:

至此,基于webpack的项目建立好了,接下来我们准备安装一些常用模块和插件。

三、模块和插件配置安装:

1、配置HTML模板

简介

刚才我们建立的index.html文件是在src下面的,但实际打包后的文件是在dist目录下的,我们可以安装一个 html-webpack-plugin 插件,来打包html模板,并将该模板指向对应的入口文件。

安装

npm i html-webpack-plugin -D

配置

修改webpack.config.js后如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        })
    ]
}

增加了插件引入和插件的配置,仔细对比前面的设置就能知道。

运行

运行前修改一下src目录下的index.html代码,取消bundle.js的引用;

再次运行 npm run dev 结果如下:

在dist目录下自动新增了一个index.html文件,并且里面自动引用了bundle.js,这是因为我们新建的index.html文件是自动指向到index.js入口的;而index.js作为入口文件又最终编译生成为bundle.js。

2、引用CSS

简介

css文件在打包完成之后也会输出到dist目录下,所以引用css仍然需要模块支持,我们现在讨论的并不是拆分后的css,而是内部样式表;也就是说,css在自动引入到html文件中的时候是以内部样式表的形式出现的。关于拆分css我们后面会讲到。

安装

引用css需要安装两个模块:style-loader和css-loader

npm i style-loader css-loader -D

其中css-loader是负责解析css的,而style-loader则负责将css以内部样式表的形式嵌入到html中,当使用插件拆分css的时候就不再需要style-loader了,因为那是以外部样式表link到html文件中的。

配置

修改webpack.config.js,增加内容如下:

module: {
         rules: [
        {
            test: /\.css$/,     // 解析css
            use: ['style-loader', 'css-loader'] // 从右向左解析
            /* 
                也可以这样写,这种方式方便写一些配置参数
                use: [
                    {loader: 'style-loader'},
                    {loader: 'css-loader'}
                ]
            */
        }
    ]
}

修改后的webpack.config.js全部内容如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,     // 解析css
                use: ['style-loader', 'css-loader'] // 从右向左解析
                /* 
                    也可以这样写,这种方式方便写一些配置参数
                    use: [
                        {loader: 'style-loader'},
                        {loader: 'css-loader'}
                    ]
                */
            }
        ]
    }
}

运行

在运行前我们需要在src目录下新建一个css目录,并新建index.css,目录代码如下:

修改index.js,增加:

import "./css/index.css";

运行 npm run dev后的目录代码如下:

目录中并没有增加css文件夹和任何css文件,但是运行dist里面的index.html文件会得到下图效果。

页面效果如下:

这是使用style-loader打包的结果,内部样式表。

3、拆分CSS

简介

通过使用extract-text-webpack-plugin插件将刚才的内部样式表拆分为外部样式表

安装

npm i extract-text-webpack-plugin@next -D

配置

修改webpack.config.js里面的module:

module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            }
        ]
    },

新增:

const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');

新增:

plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
        }),
        // 拆分后会把css文件放到dist目录下的css/style.css
        new ExtractTextWebpackPlugin('css/style.css')  
    ]

新增new ExtractTextWebpackPlugin('css/style.css') 后,会在dist目录下生产一个css文件夹,且src目录下的css最终会合并到这个style.css文件中,如果不想叫style.css,可以修改。

修改完毕后的webpack.config.js如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
     plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
        }),
        // 拆分后会把css文件放到dist目录下的css/style.css
        new ExtractTextWebpackPlugin('css/style.css')  
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            }
        ]
    }
}

运行

运行 npm run dev后的目录代码如下:


4、引用Less

简介

less作为前端css编译工具广受欢迎,它在前端的使用方式有两种,一种是引入less.js文件来动态编译less代码,这必然是降低了程序的响应时间;第二种就是使用工具或lessc来手动编译转换less代码为css;我们现在要做的事情是在webpack这个自动化工具中配置less,让它变得自动起来。

安装

npm install less less-loader --save-dev

配置

修改webpack.config.js,增加:

{
    test:/\.less$/,
    use:ExtractTextPlugin.extract({
        fallback:"style-loader",
        use:[{
            loader:"css-loader"
        },{
            loader:"less-loader"
        }]
    })
}

修改完毕后的webpack.config.js如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            }
        ]
    }
}

运行

运行前需要做的修改如下:

修改src目录下的index.html文件,新增一个class为less的div

在src目录下新建一个less文件夹,并新建index.less文件

在index.js中引入less文件夹下的index.less文件

运行npm run dev后的目录代码如下:

这里的style.css是将index.css和index.less的内容合并后的结果,至于如何拆分开,我们在多入口文件的时候再说。

5、引用Sass

简介

sass引入同less,不再多述。

安装

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

同时安装了node-sass和sass-loader,其中node-sass安装过程可能会因为国外镜像原因或网络原因出错,但请单独安装node-sass和sass-loader;node-sass安装失败的解决办法主要推荐两个:

第一:

在项目根目录创建.npmrc文件,复制下面代码到该文件。

创建.npmrc文件需要在wp目录下输入命令: type nul>.npmrc

phantomjs_cdnurl=http://cnpmjs.org/downloads
sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
registry=https://registry.npm.taobao.org

保存后 删除之前安装失败的包(第一次安装请跳过此步)

npm uninstall node-sass

重新安装

npm install node-sass

第二:

设置变量 sass_binary_site,指向淘宝镜像地址。示例:

npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/

// 也可以设置系统环境变量的方式。示例
// linux、mac 下
SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ npm install node-sass

// window 下
set SASS_BINARY_SITE=https://npm.taobao.org/mirrors/node-sass/ && npm install node-sass

配置

修改webpack.config.js,新增配置:

{
    test: /\.scss$/,     // 解析less
    // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
    use: ExtractTextWebpackPlugin.extract({
        // 将css用link的方式引入就不再需要style-loader了
        use:[{
            loader:"css-loader"
            },{
                loader:"sass-loader"
            }]      
        })
}

修改后的完整webpack.config.js代码如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use: 'css-loader'       
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
        ]
    }
}

运行

运行前需要做的修改如下:

修改src目录下的index.html文件,新增一个class为sass的div

在src目录下新建一个sass文件夹,并新建index.scss文件

在index.js中引入sass文件夹下的index.scss文件

运行npm run dev后的目录代码如下:

这里的style.css是将index.css、index.less和index.scss的内容合并后的结果,至于如何拆分开,我们在多入口文件的时候再说。

6、CSS3自动增加前缀

简介

我们在css或less、sass文件中常常会编写一些CSS3代码,有些时候这些css3代码需要指明私有前缀,这无疑增加了很多工作,可以使用 postcss-loader 插件来帮我们自动增加。

安装

npm install --save-dev postcss-loader autoprefixer

配置

postcss-loader的配置不同于前面的几个文件,它需要在wp根目录下新建一个postcss.config.js文件,并在里面添加如下代码:

module.exports = {
    plugins: [require('autoprefixer')]  // 引用该插件即可了
}

然后对需要的css或less、sass模块做出修改,比如你需要在css中增加css3前缀的功能,那就在css模块中增加postcss-loader,如下:

{
   test: /\.css$/,     // 解析css
   use: ExtractTextWebpackPlugin.extract({
        use:[{
            loader:"css-loader"
            },{
                loader:"postcss-loader"
            }],   
    })
},

less模块和sass模块操作同理。

修改后的webpack.config.js代码如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   

                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
        ]
    }
}

运行

运行前修改src/css/index.css文件,增加了transform css3代码,如下:

运行 npm run dev 后的目录代码如下:

刚刚修改的css3代码,自动增加了私有前缀。

7、CSS中的图片引用处理

简介

css中引用图片主要引用file-loader和url-loader,其中file-loader主要解决引用路径问题,url-loader主要解决图片的加载优化问题,可以设置一个阈值,比如将8k以下的图片转换为data-url的形式直接引用到html文件中,从而减少请求次数,达到优化目的。

安装

npm install --save-dev file-loader url-loader

配置

修改webpack.config.js,增加如下代码:

{
    test: /\.(jpe?g|png|gif)$/,
    use: [
        {
            loader: 'url-loader',
            options: {
                limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                outputPath: 'images/'   // 图片打包后存放的目录
            }
        }
    ]
},

并增加红框中的内容

修改后的webpack.config.js文件如下:

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

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new ExtractTextWebpackPlugin('css/style.css') 
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   
                    publicPath: '../'

                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
        ]
    }
}

运行

运行前在src目录下新建image文件夹,在文件夹当中放一个图片做测试,如图:

修改src目录下的index.html文件:

修改src/css/index.css文件

运行 npm run dev后的效果为:

8、HTML中的图片引用处理

简介

同css中的图片处理,在html文件中使用img标签引用图片同样存在类似问题,需要安装 html-withimg-loader 模块

安装

npm install --save-dev html-withimg-loader

配置

修改webpack.config.js文件,新增:

{
    test: /\.(htm|html)$/,
    use: 'html-withimg-loader'
}

运行

修改src目录下的 index.html文件新增img标签

运行 npm run dev 后的效果如图:

9、iconfont字体引用

简介

原理同上

安装

不需要安装,因为已经安装过file-loader了。

配置

修改webpack.config.js文件,新增:

{
    test: /\.(eot|ttf|woff|svg)$/,
    use: 'file-loader'
},

运行

拷贝一个iconfont字体图标库到src/css文件夹下,如图:

在src/index.html文件中新增 span标签如下:


在src/index.js文件新增 iconfont.css引入如下:

运行 npm run dev 后的效果如下:

页面中将增加一个麦当劳的M标志,证明成功使用了字体图标。

10、Babel安装

简介

ES6因为包含广泛,ES2015,2016,2017等,使用中对ES6的转码是必须的,所以我们采用了babel来转码。

安装

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

这个安装过程可能比较慢,也可能会出现一些关于Parse , Json等的解析错误,出现类似的错误请按照下面两个方法解决:

第一:

运行 : npm cache clean –force 之后再运行上面的安装命令。

第二:

如果问题没有顺利解决,运行:npm install --registry=https://registry.npm.taobao.org --loglevel=silly
之后再运行安装命令。

配置

修改webpack.config.js,新增:

{
    test:'/\.(js|jsx)$/',
    use: 'bable-loader',
    include: /src/,          // 只转化src目录下的js
    exclude: /node_modules/  // 排除掉node_modules,优化打包速度
}

运行

运行前,在wp根目录下新建.babelrc文件

type nul>.babelrc

并在里面新增如下代码:

{
    "presets": ["env", "stage-0"]   // 从右向左解析
}

目录代码如下:

运行 npm run dev后观察代码的变化,事实上没有安装babel的时候,webpack也可以解码es6,但考虑到es6代表广泛,所以还是安装了babel解码。

11、JS代码压缩

在webpack.config.js中新增:

mode: 'development'

表示开发环境,不压缩代码。

mode: 'production'

表示生产环境,压缩代码。

12、CSS代码压缩

简介

CSS代码压缩需要安装插件:

optimize-css-assets-webpack-plugin

安装

npm install optimize-css-assets-webpack-plugin --save-dev

配置

在webpack.config.js中新增

const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require('cssnano'),
      cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
      canPrint: true
    })

目录代码如图:

运行

运行 npm run dev 后的目录代码如下:

13、HTML代码压缩

html代码压缩不用再安装额外的插件和模块,修改webpack.config.js中的html插件为:

new HtmlWebpackPlugin({
        template: './src/index.html',   
        //filename: 'index.html',
        //chunks: ['index'],   // 对应关系,index.js对应的是index.html
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }),

目录代码如图:

运行 npm run dev后可见dist目录下的index.html已经压缩了。

14、安装第三方类库Jquery

简介

jquery作为前端必需的第三方类库,安装是它是一个示范作用,其他的第三方类库安装可以参考jquery 的安装。

安装

npm install jquery --save-dev

配置

jquery的引用要用到webpack,所以修改webpack.config.js,新增:

const Webpack = require('webpack');

还要新增:

new Webpack.ProvidePlugin({
        $:'jquery'
    }),

备注:如果项目还引用了Bootstrap,那jquery的配置还需要修改为如下:

new Webpack.ProvidePlugin({
        $:'jquery',
        jQuery:'jquery'
    }),

修改后的webpack.config.js代码如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const Webpack = require('webpack');

module.exports = {
    mode: 'development',//production
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        // new HtmlWebpackPlugin({
        //     // 在src目录下创建一个index.html页面当做模板来用
        //     template: './src/index.html',
        // }),
        new HtmlWebpackPlugin({
            template: './src/index.html',   
            //filename: 'index.html',
            //chunks: ['index'],   // 对应关系,index.js对应的是index.html
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        new ExtractTextWebpackPlugin('css/style.css'),
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        }),
        new Webpack.ProvidePlugin({
            $:'jquery'
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   
                    publicPath: '../'
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }

        ]
    },
}

运行

运行前修改src目录下的index.js文件,新增:

$('div').css('border', '10px solid white');

目录代码如下:

运行npm run dev后的效果如下:

15、多页面多入口打包

在实际的开发中,我们不可能只有一个页面,常常需要很多页面,那打包多页面就很实际了,多页面就需要多入口,也就是需要多个.js文件;所以在src目录下新建:login.html和login.js,其中login.js作为login.html页面的入口文件。

在src/css下新建login.css文件作为修饰login.html的css,目录代码如图:

login.html

login.css

login.js

新增完毕页面后,还需要修改webpack.config.js文件:

修改入口文件为:

修改出口文件为:

修改html插件为:

修改css插件为:

修改后的webpack.config.js代码如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const Webpack = require('webpack');

module.exports = {
    mode: 'development',//production
    // entry: './src/index.js',    // 入口文件
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // output: {
    //     filename: 'bundle.js',      // 打包后的文件名称
    //     path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    // },
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        // 通过new一下这个类来使用插件
        // new HtmlWebpackPlugin({
        //     // 在src目录下创建一个index.html页面当做模板来用
        //     template: './src/index.html',
        // }),
        // new HtmlWebpackPlugin({
        //     template: './src/index.html',   
        //     // filename: 'index.html',
        //     // chunks: ['index'],   // 对应关系,index.js对应的是index.html
        //     minify: {
        //         removeAttributeQuotes:true,
        //         removeComments: true,
        //         collapseWhitespace: true,
        //         removeScriptTypeAttributes:true,
        //         removeStyleLinkTypeAttributes:true
        //     }
        // }),
        new HtmlWebpackPlugin({
            template: './src/index.html',   
            filename: 'index.html',
            chunks: ['index'],   // 对应关系,index.js对应的是index.html
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],   // 对应关系,login.js对应的是login.html
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        // new ExtractTextWebpackPlugin('css/style.css'),
        new ExtractTextWebpackPlugin('css/[name].css'),
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        }),
        new Webpack.ProvidePlugin({
            $:'jquery'
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader'   
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"postcss-loader"
                    }],   
                    publicPath: '../'
                })
            },
            {
                test:/\.less$/,
                use:ExtractTextWebpackPlugin.extract({
                    fallback:"style-loader",
                    use:[{
                        loader:"css-loader"
                    },{
                        loader:"less-loader"
                    }]
                })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }

        ]
    },
}

运行 npm run dev 后的 dist目录结构如下:

16、优化多页面多入口

由于每次新增一个页面都需要修改webpack.config.js这很麻烦,所以修改后的webpack.config.js如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const Webpack = require('webpack');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const glob = require("glob");

var webpackConfig = {
    mode: 'development',//production
    // entry: './src/index.js',    // 单页面入口文件
    // 多页面配置
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // 出口文件  
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        new ExtractTextWebpackPlugin('css/[name].css'),

        new Webpack.ProvidePlugin({
            $:'jquery'
        }),
        new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,     // 解析css
                // use: ['style-loader', 'css-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader',
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"postcss-loader"
                        }],
                    publicPath: '../'      
                })
            },
            {
                test: /\.less$/,     // 解析less
                // use: ['style-loader', 'css-loader','less-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"less-loader"
                        }]      
                    })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }
        ]
    }
}

function getView(globPath){
    let files = glob.sync(globPath);

    let entries = {},
    entry, dirname, basename, pathname, extname;

    files.forEach(item => {
        entry = item;
        dirname = path.dirname(entry);//当前目录
        extname = path.extname(entry);//后缀
        basename = path.basename(entry, extname);//文件名
        pathname = path.join(dirname, basename);//文件路径
        if (extname === '.html') {
            entries[pathname] = './' + entry;
        } else if (extname === '.js') {
            entries[basename] = entry;
        }
    });

    return entries;
}

let pages = Object.keys(getView('./src/*html'));

pages.forEach((pathname) => {
    let htmlname = pathname.split('src/')[1];
    let conf = {
        filename: `${htmlname}.html`,
        template: `${pathname}.html`,
        // hash: true,
        chunks:[htmlname],
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }

    webpackConfig.plugins.push(new HtmlWebpackPlugin(conf));
});

module.exports = webpackConfig;

除此之外不用修改其他任何文件。

17、热更新

简介

每次运行和更新代码都输入npm run dev命令太麻烦,安装热更新来解决该问题,每次改动代码后,只需要保存代码并刷新页面即可,不用再执行命令。

安装

npm install webpack-dev-server --save-dev

配置

修改webpack.config.js 新增插件:

new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件

新增热更新配置:

devServer: {
    // 设置服务器访问的基本目录
    contentBase:path.resolve(__dirname,'dist'), //最好设置成绝对路径
    // 设置服务器的ip地址,可以是localhost
    host:'localhost',
    // 设置端口
    port:8090,
    // 设置自动打开浏览器
    open:true,
    // 设置热更新
    hot:true
}

修改后的webpack.config.js如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
const Webpack = require('webpack');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const glob = require("glob");

var webpackConfig = {
    mode: 'development',//production
    // entry: './src/index.js',    // 单页面入口文件
    // 多页面配置
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // 出口文件  
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        new ExtractTextWebpackPlugin('css/[name].css'),

        new Webpack.ProvidePlugin({
            $:'jquery'
        }),
        new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件
        new OptimizeCssAssetsPlugin({
          assetNameRegExp: /\.css$/g,
          cssProcessor: require('cssnano'),
          cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
          canPrint: true
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/,     // 解析css
                // use: ['style-loader', 'css-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    // use: 'css-loader',
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"postcss-loader"
                        }],
                    publicPath: '../'      
                })
            },
            {
                test: /\.less$/,     // 解析less
                // use: ['style-loader', 'css-loader','less-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"less-loader"
                        }]      
                    })
            },
            {
                test: /\.scss$/,     // 解析less
                // use: ['style-loader', 'css-loader','sass-loader'] // 从右向左解析
                use: ExtractTextWebpackPlugin.extract({
                    // 将css用link的方式引入就不再需要style-loader了
                    use:[{
                        loader:"css-loader"
                        },{
                            loader:"sass-loader"
                        }]      
                    })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小于8k的图片自动转成base64格式,并且不会存在实体图片
                            outputPath: 'images/'   // 图片打包后存放的目录
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: 'file-loader'
            },
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            }
        ]
    },
    devServer: {
        // 设置服务器访问的基本目录
        contentBase:path.resolve(__dirname,'dist'), //最好设置成绝对路径
        // 设置服务器的ip地址,可以是localhost
        host:'localhost',
        // 设置端口
        port:8090,
        // 设置自动拉起浏览器
        open:true,
        // 设置热更新
        hot:true
    }
}

function getView(globPath){
    let files = glob.sync(globPath);

    let entries = {},
    entry, dirname, basename, pathname, extname;

    files.forEach(item => {
        entry = item;
        dirname = path.dirname(entry);//当前目录
        extname = path.extname(entry);//后缀
        basename = path.basename(entry, extname);//文件名
        pathname = path.join(dirname, basename);//文件路径
        if (extname === '.html') {
            entries[pathname] = './' + entry;
        } else if (extname === '.js') {
            entries[basename] = entry;
        }
    });

    return entries;
}

let pages = Object.keys(getView('./src/*html'));

pages.forEach((pathname) => {
    let htmlname = pathname.split('src/')[1];
    let conf = {
        filename: `${htmlname}.html`,
        template: `${pathname}.html`,
        // hash: true,
        chunks:[htmlname],
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }

    webpackConfig.plugins.push(new HtmlWebpackPlugin(conf));
});

module.exports = webpackConfig;

修改wp根目录下的package.json文件:

修改后的package.json如下:

{
  "name": "wp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --mode development",
    "dev": "webpack-dev-server --mode development"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^9.1.5",
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.4",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^1.0.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^2.0.0",
    "html-webpack-plugin": "^3.2.0",
    "html-withimg-loader": "^0.1.16",
    "jquery": "^3.3.1",
    "less-loader": "^4.1.0",
    "node-sass": "^4.9.3",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  }
}

运行

运行 npm run dev 后的cmd命令行效果如下:

18、安装Vue

简介

vue是在使用中,我们对组件模板的引用有一种单文件模板的使用形式,这种模板的引用就需要用到ES6的模块技术,所以将vue打包到webpack里面。

安装

安装vue:

npm install vue --save-dev

安装vue-loader和vue-template-compiler

npm install vue-loader vue-template-compiler --save-dev

配置

修改webpack.config.js:

新增:

...
const VueLoaderPlugin = require('vue-loader/lib/plugin');
...
new VueLoaderPlugin(),
...
{ test: /\.vue$/, use: 'vue-loader' },
...
resolve: {
    alias: {
        'vue': 'vue/dist/vue.js'
    }
}
...

修改后的代码示例如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const Webpack = require('webpack');

module.exports = {
    entry: './src/index.js',    // 入口文件
    output: {
        filename: 'bundle.js',      // 打包后的文件名称
        path: path.resolve('dist')  // 打包后的目录,必须是绝对路径
    },
    plugins: [
        // 通过new一下这个类来使用插件
        new HtmlWebpackPlugin({
            // 在src目录下创建一个index.html页面当做模板来用
            template: './src/index.html',
        }),
        new VueLoaderPlugin(),
        new Webpack.HotModuleReplacementPlugin(),//调用webpack的热更新插件
    ],
    module: {
        rules: [
            {
                test:'/\.(js|jsx)$/',
                use: 'bable-loader',
                include: /src/,          // 只转化src目录下的js
                exclude: /node_modules/  // 排除掉node_modules,优化打包速度
            },
            { test: /\.vue$/, use: 'vue-loader' },
        ]
    },
    devServer: {
        // 设置服务器访问的基本目录
        contentBase:path.resolve(__dirname,'dist'), //最好设置成绝对路径
        // 设置服务器的ip地址,可以是localhost
        host:'localhost',
        // 设置端口
        port:8090,
        // 设置自动打开浏览器
        open:true,
        // 设置热更新
        hot:true
    },
    resolve: {
        alias: {
            'vue': 'vue/dist/vue.js'
        }
    }
}

运行

输入npm run dev运行查看效果,这里不再列出.vue的编写和vue相关的引入了。直接查看示例即可。

你可能感兴趣的:(webpack 4.0使用指南)