基于webpack4.0构建完整项目

2,151 阅读10分钟

一、初识webpack

javascript 应用程序的静态模块打包工具,其作用:分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),
并生成一个或多个 bundle,将其打包为合适的格式以供浏览器使用

概念图解: webpack官网

二、环境安装

如果具备该环境,此步骤可以跳过

Homebrew
  打开终端,执行以下命令安装Homebrew:
  
  ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Node
  打开终端,执行以下命令安装node: brew install node
     
  查看版本,检查是否安装成功: node -v   npm -v
镜像切换 Cnpm
  打开终端,执行以下命令安装cnpm:
  
  npm install cnpm -g --registry=https://registry.npm.taobao.org
  
  查看版本,检查是否安装成功: cnpm -v 
webpack

在webpack4.x之后,其脚手架webpack-cli需要单独安装:

npm install webpack webpack-cli --global    //这是安装全局webpack及webpack-cli模块

npm install webpack webpack-cli --save-dev  //这是安装本地项目模块

三、小试牛刀

  • 新建文件目录 webpack-simple,并生成package.json
  1. mkdir webpack-simple
  
  2. npm init 或 npm init -y (指定模版生成package.json)

  3. npm install webpack webpack-cli --save-dev
  • 项目结构并生成

根目录下新建 src 文件夹 和 dist 文件夹,创建对应的脚本文件:

 1. dist文件夹下 新建 index.html
 
 2. src文件夹下 新建 index.js
 
 3. src文件夹下 新建 hello.js

index.html: 引入打包后的js文件

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Webpack Project</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
    <!--这是打包之后的js文件,我们暂时命名为bundle.js-->
  </body>
</html>

hello.js

module.exports = function() {
  let hello = document.createElement('div')
  hello.innerHTML = 'welcome to webpack knowledge world!'
  return hello
}

在index.js中引入 hello.js:

const hello = require('./hello')
document.querySelector('#root').appendChild(hello());

在以上操作过程中,已经完成了基本的文件组成,同时也把hello.js 合并到 index.js中,打包时,只需要输出index.js文件即可

// 在终端中根路径下使用如下命令进行打包:

 webpack src/index.js output dist/bundle.js

执行结果可以看到 把 src 文件夹下的 index.js 文件打包到 dist 文件下的 bundle.js,这时就生成了 bundle.js 供 index.html 文件引用。那么打开index.html就可以看到完整的页面效果了

  • webpack.config.js

根目录下新建配置文件 webpack.config.js 用来配置打包方式:

const path = require('path') // 处理绝对路径
module.exports = {
  entry: path.join(__dirname, '/src/index.js'), // 入口文件
  output: {
    path: path.join(__dirname, '/dist'), //打包后的文件存放的地方
    filename: 'bundle.js' //打包后输出文件的文件名
  }
}

在终端根路径下执行命令 webpack 就可进行打包,该命令会自动引用 webpack.config.js 文件中的配置选项

  • 构建本地服务器并优化执行方式
//安装 webpack-dev-server
npm i webpack-dev-server -D
// webpack.config.js
const path = require('path')
module.exports = {
  entry: path.join(__dirname, '/src/index.js'), // 入口文件
  output: {
    path: path.join(__dirname, '/dist'), //打包后的文件存放的地方
    filename: 'bundle.js' //打包后输出文件的文件名
  },
  devServer: {
    hot:true, //开启热更新
    contentBase: './dist', // 本地服务器所加载文件的目录
    port: '8088', // 设置端口号为8088
    inline: true, // 文件修改后实时刷新
    historyApiFallback: true //不跳转
  }
}
// package.json文件更新scripts命令
{
  "name": "webpack-simple",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack", //项目打包
    "watch": "webpack --watch",// 加--watch自动监听代码的变化
    "dev": "webpack-dev-server --open" //配置热更新
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.42.0",
    "webpack-cli": "^3.3.11"
  },
  "dependencies": {
    "webpack-dev-server": "^3.10.3"
  }
}

采用命令进行本地运行或项目打包

 //终端下执行命令
 1. npm run dev (webpack-dev-server 就是启动服务器的命令,--open 是用于启动完服务器后自动打开浏览器)  //启动服务器 
 2. npm run build  //执行打包命令

此时,基本的项目配置已经准备完成,只需要输入 npm run dev 就可以在http://localhost:8088/中查看页面 效果了。

Loader

webpack可以使用loader 来预处理那些非 JavaScript 文件,就是通过使用不同的Loader,webpack可以把不同的静态文件都编译成js文件,比如css,sass,less,ES6/7,vue,JSX等

概念图解: 官网

处理JS文件
  • babel-loader
作用: 实现对使用了ES2015+语法的.js文件进行处理.

命令:

npm/cnpm install babel-loader --save-dev
  • babel-core
作用 : 在于提供一系列api。这便是说,当webpack使用babel-loader处理文件时,babel-loader实际上调用了babel-core的api

命令:

 npm/cnpm install babel-core --save-dev
  • babel-preset-env
作用: 在于告诉babel使用哪种转码规则进行文件处理

命令:

 npm/cnpm install babel-preset-env --save-dev
  • webpack.config.js的配置
const path = require('path');//物理路径
//__dirname,当前运行环境下的变量,也就是当前环境下的绝对路径,后面会跟着一个相对路径
{
   ...
    
   module:{
      rules:[
        {
          test:/\.js$/,
          include:path.resolve(__dirname, 'src'),
          exclude: path.resolve(__dirname,"node_modules"), // /node_modules/, //指定排除处理的范围文件,提高打包的速度,可以是正则表达式,还有绝对路径
          loader: "babel-loader"
        }
      ]
   } 

   ...
}
  • 项目构建

在基础的项目结构下,src目录下新建 babel-test.js文件,并引入到index.js中

//babel-test.js代码
module.exports = {
    showToast:function () {
        alert('用来测试babel-loader引入的弹窗')
    }
}
//index.js代码
const hello = require('./hello')
const babelTest = require('./babel-test')

document.querySelector('#root').appendChild(hello());
babelTest.showToast()

执行命令

npm run dev

如出现错误:

Error: Cannot find module '@babel/core'

那是因为babel-loader的版本过高, 找不到babel-core. 两者之间不匹配, 这个时候的办法, 是先重新安装babel-loader,回退版本到7.0多

“cnpm install babel-loader@7.1.5 --save-dev”

或者 “npm install @babel/core --save-dev”

命令成功执行后,可以在浏览器 8080页面,查看到babel-test中 引入的弹窗效果。这样对于babel-loader的配置,也基本成功完成了.

处理CSS文件
  • style-loader
作用: 能够在需要载入的html中创建一个<style></style>标签,style-loader加载到的css样式动态的添加该标签中.

命令:

npm/cnpm install style-loader --save-dev
  • css-loader
作用: 允许在js中import一个css文件,会将css文件当成一个模块引入到js文件中. 只会加载引入到js文件中的css文件.

命令:

npm/cnpm install css-loader --save-dev
  • 简单配置css样式支持

在基础的项目结构下,src目录下新建 style/style.css文件,并引入到index.js中

<!--style/style.css代码-->

.container{
    width:200px;
    height:200px;
    background-color:red
}
//index.js代码
import './style/style.css' ; //对css文件进行引入
const hello = require('./hello')
const babelTest = require('./babel-test')

document.querySelector('#root').appendChild(hello());
babelTest.showToast()
<!--dist/index.html代码-->
<body>
<div id="root"></div>
<div class="container"></div>
<script src="dist/bundle.js"></script>
<!--这是打包之后的js文件,我们暂时命名为bundle.js-->
</body>
<!--webpack.config.js配置-->
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/, //匹配以css为后缀的文件
        use: ['style-loader', 'css-loader'],//loader的执行顺序是从右向左,从下到上。css-loader:分析几个css文件之间的关系,最终合并为一个css。style-loader:在得到css生成的内容时,把其挂载到html的head里,成为内联样式。
      },
    ],
  },
};

执行命令 npm run dev 可以查看到css样式已经成功的加载到页面中

处理静态SASS、LESS文件
  • sass-loader
 作用: 对项目中scss文件进行处理

命令:

 npm/cnpm install sass-loader --save-dev
 
 npm/cnpm install node-sass --save-dev
  • less-loader
 作用: 对项目中的less文件进行处理

命令:

 cnpm install less --save-dev

 npm/cnpm install less-loader --save-dev
  • postcss-loader
 作用: 其主要是对css文件的预处理,autoprefixer是它的一个插件,主要是对css文件添加兼容性前缀

常见浏览器前缀:

  1. Trident内核:主要代表为IE浏览器, 前缀为-ms
  
  2. Gecko内核:主要代表为Firefox, 前缀为-moz
  
  3. Presto内核:主要代表为Opera, 前缀为-o

  4. Webkit内核:产要代表为Chrome和Safari, 前缀为-webkit

命令:

 npm/cnpm install postcss-loader --save-dev
 
 cnpm install autoprefixer --save-dev. //属于postcss的插件

在项目中,提供两种方式分别对 autoprefixer 的配置支持

//1.在项目根目录下创建 postcss.config.js文件

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

//2. 直接在webpack.config.js文件配置对loader的特别支持 如下(webpack.config.js的配置)
  • webpack.config.js的配置
module.exports = {
    ...
    module: {
          test:/\.(sc|le|c)ss$/, // 项目中如果有多个ss文件结尾时,正则表达式可以这么使用,最新执行的再前面
          use:[{
                 loader:'style-loader'
             },{
                 loader:'css-loader',
                 options:{
                    importLoaders:1, ////如果sass文件里还引入了另外一个sass文件,另一个文件还会从postcss-loader向上解析。如果不加,就直接从css-loader开始解析。
                    modules: true //开启css的模块打包。css样式不会和其他模块发生耦合和冲突

                 }
             },{
                 loader:"less-loader"
             },{
                 loader:"sass-loader"
             },{
                 loader:'postcss-loader', //autoprefixer使用该插件为各浏览器支持的属性加上前缀
                 options:{
                     plugins:[require("autoprefixer")("last 5 versions")]
                    
                 } 
             },
          ],
           include:path.resolve(__dirname, 'src'),
       },
};
处理资源文件
  • file-loader的使用
 作用: 对项目中引入的资源文件(图片)进行处理,解决CSS等文件中的引入图片路径问题

命令:

 npm/cnpm install file-loader --save-dev
//webpack.config.js配置
module.exports = {
    //配置模块,主要用来配置不同文件的加载器
  module: {
      //配置模块规则
    rules: [
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/, //正则匹配要使用相应loader的文件
        use: [
          {
            loader: 'file-loader', //要用到的loader
              options: {
                  //palceholder占位符
                  name:'[name].[ext]', //打包后的图片名字,后缀和打包的之前的图片一样
                  outputPath: 'images/' //图片打包后的地址
              },
          },
        ],
      },
    ],
  },
};

  • url-loader的使用
作用:将小图片转换成base64格式,其已经具备了file-loader的功能,使用时,可以不引用file-loader.
url-loader可以将图片转成base64字符,能更快的加载图片,一旦图片过大,就会使用file-loader的加载本地图片

命令:

 npm/cnpm install url-loader --save-dev
<!--webpack.config.js配置-->
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif|bmp/)$/i,
        use: [
          {
            loader: 'url-loader',
            options: {
              name:'[name].[ext]',
              outputPath: 'images/',
              limit: 8192 //小于8192b,就可以转化成base64格式。大于就会打包成文件格式
            }
          }
        ]
      }
    ]
  }
}

  • file-loader和url-loader使用注意:
  1. 在css文件中对图片资源文件的引入可以使用相对路径:
   
   app.css文件中:
   
   .imgClass{
      width:400px;
      height: 400px;
     background: url('../assets/test.jpg');
    }
   
   .imgSize{
        width:400px;
       height: 400px;
    }
   
  2. 在html中如果使用img标签的src 对图片进行使用,需要“使用绝对路径”. 如果要使用相对路径,则需要如下:

   <div class="imgClass"></div>
   <img class="imgSize" src="${require('./src/assets/bg.jpg')}"/>
  • image-webpack-loader
 作用:对引入项目中的图片文件进行压缩处理

命令:

 npm/cnpm install image-webpack-loader --save-dev
<!--webpack.config.js配置 -->
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif|bmp/)$/i,
        use: [
          {
             loader: 'url-loader',
             options: {
                name:'[name].[ext]',
                outputPath: 'images/',
                limit: 8192 //小于8192b,就可以转化成base64格式。大于就会打包成文件格式
            }
          },
           {
             loader:'image-webpack-loader',  //对图片资源进行压缩处理
           }
        ]
      }
    ]
  }
}

处理HTML文件
  • html-loader
作用: 对项目中引入的模版html文件进行处理(必须在js文件中引入)

命令:

 npm/cnpm install html-loader --save-dev
完整的Loader支持配置
  • 项目结构

webpack-simple项目中,我们的文件结构树如下:

在src目录下,存在components文件夹 和 index.js 文件, 代码引入如下:

//components/layer.js代码

import template from './layer.html'
import "./layer.css";
// import "./layer.less";

function layer (){
 return{
  name:"layer",
  tpl:template
 }
}

//导出
export default layer;
//components/layer.html代码

<div class="layer">
 <div>this is a layer</div>
</div>
//index.js对layer模版的引入
import './style/style.css' ; //对css文件进行引入

//模版引入
import Layer from './components/layer/layer.js'

const hello = require('./hello')
const babelTest = require('./babel-test')

document.querySelector('#root').appendChild(hello());
babelTest.showToast()

const App = function (){
    var dom = document.getElementById('layer');
    dom.innerHTML = new Layer().tpl;
    console.log(dom);
    console.log(Layer);
}
new App();

<!--index.html中使用layer模版-->
<body>
<div id="root"></div>
<div class="container"></div>
<div id="layer"></div>
<script src="dist/bundle.js"></script>
<!--这是打包之后的js文件,我们暂时命名为bundle.js-->
</body>
  • webpack.config.js的配置
//处理绝对路径
const path = require('path');
const webpack = require('webpack');

module.exports = {
    //默认是production,打包的文件默认被压缩。开发时可以设置为development,不被压缩
    mode: 'production',
    entry: path.join(__dirname, 'src/index.js'), //入口文件
    output: {
        path: path.resolve(__dirname, 'dist'), //定位,输出文件的目标路径
        filename: 'bundle.js', //可自定命名js/[name].js,打包后输出文件的文件名称, 文件名默认[name].js, 可以在前面加上相对路径,生成包裹js文件的文件夹
    },
    devServer: {
        hot: true,
        contentBase: './dist', //本地服务器所加载文件的目录
        port: '8088', //设置端口号8088
        inline: true, //文件修改后热更新
        historyApiFallback: true // 不跳转
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: "babel-loader",
                include: path.resolve(__dirname, 'src'),
                exclude: path.resolve(__dirname, "node_modules"), // /node_modules/, //指定排除处理的范围文件,提高打包的速度,可以是正则表达式,还有绝对路径
            }, {
                test: /\.(sc|le|c)ss$/, // 项目中如果有多个ss文件结尾时,正则表达式可以这么使用,最新执行的再前面
                // loader:'style-loader!css-loader!less-loader' 没有postcss-loader可以直接这样使用
                use: [{
                    loader: 'style-loader'
                }, {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 1
                    }
                }, {
                    loader: "less-loader"
                }, {
                    loader: "sass-loader"
                }, {
                    loader: 'postcss-loader', //autoprefixer使用该插件为各浏览器支持的属性加上前缀
                    options: {plugins: [require("autoprefixer")("last 5 versions")]}
                },
                ],
                include: path.resolve(__dirname, 'src'),
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,  //使用file-loader对资源文件的引入,i不区分大小写
                include: path.resolve(__dirname, 'src'),
                use: [
                    //  {
                    //   loader:'file-loader',
                    //   options:{
                    //       name:'assets/[name]-[hash:5].[ext]',  //设置资源图片打包后的地址
                    //   }
                    // },
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 20000,   //限制图片的最大字节
                            name: 'assets/[name]-[hash:5].[ext]',  //设置资源图片打包后的地址
                        }
                    },
                    {
                        loader: 'image-webpack-loader',  //对图片资源进行压缩处理
                    }
                ]
            },
            {
                test: /\.html$/,  //使用html-loader对html模版内容进行引入.
                // include:path.resolve(__dirname, 'src'),
                loader: "html-loader"

            }]
    }
}

Plugin

 plugin是webpack的支柱, 主要是为了解决loader无法实现的其他事情.想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。
 多数插件可以通过选项(option)自定义,你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例

概念图解:官网

  • webpack-dev-server
作用: 搭建本地服务器,实现热更新,可解决每次在src里编写完代码都需要手动重新运行 npm run dev

命令:

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

属性:

1. contentBase :配置开发服务运行时的文件根目录

2. open :自动打开浏览器

3. host:开发服务器监听的主机地址

4. compress :开发服务器是否启动gzip等压缩

5. port:开发服务器监听的端口
//处理绝对路径
const path = require('path');
const webpack = require('webpack');

module.exports = {
    //默认是production,打包的文件默认被压缩。开发时可以设置为development,不被压缩
    mode: 'production',
    entry: path.join(__dirname, 'src/index.js'), //入口文件
    output: {
        path: path.resolve(__dirname, 'dist'), //定位,输出文件的目标路径
        filename: 'js/[name].js', //打包后输出文件的文件名称, 文件名默认[name].js, 可以在前面加上相对路径,生成包裹js文件的文件夹
    },
    //本地服务
    devServer: {
        hot: true,开启热更新
        contentBase: './dist', //本地服务器所加载文件的目录
        port: '8088', //设置端口号8088
        inline: true, //文件修改后热更新
        historyApiFallback: true // 不跳转
    }
}
//package.json配置
{
  ...
  "name": "webpack-simple",
  "version": "1.0.0",
  "description": "webpack knowledge",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "dev": "webpack-dev-server --open"
    "watch": "webpack --watch",// 加--watch自动监听代码的变化

  },
  "keywords": [],
  "author": "chonglou",
  "license": "ISC",
  ...
}

  • html-webpack-plugin
作用: 打包项目中的html文件, 并生成对应打包的html文件.

命令:

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

属性:

   1.file: 指定生成的文件
   
   2.filename: 指定生成的文件名称, 优先级比file高, 两者取一即可
   
   3.template: 需要被打包的html文件路径
   
   4.inject: 主要是指定引入的js文件写入到html文件的位置. 
             主要有true(默认值,body底部)、body(body底部)、head(html标签的head)、false(不写入生成的js文件,基本不会用)
   
   5.minify对象:主要是对html文件进行压缩,可去npm官网(https://www.npmjs.com/package/html-webpack-plugin)查看对应的属性配置
  
   6.chunks:指定哪些需要被引入打包的模块
   
   7.excludeChunks:指定哪些不需要被引入打包的模块,而其他的chunks将会被引入. 且与优先级高于chunks,
                    也就是说当两者同时存在时,excludeChunks如果包含chunks中的chunk,则该chunk也不会被引入
//webpack.config.js配置
   const path = require('path');
   const HtmlWebpackPlugin = require('html-webpack-plugin'); //打包html文件

   module.exports = {
       entry: './src/index.js',
       output: {  
          path: path.resolve(__dirname, 'dist'), //定位,输出文件的目标路径
          filename: 'js/[name].js',//文件名默认[name].js, 
    },

    // webpack 中对于plugin的学习
    plugins: [ //数组, 支持生成多页面的html文件
        new HtmlWebpackPlugin({ //将模板的头部和尾部添加css和js模板,dist 目录发布到服务器上,项目包。可以直接上线
            file: 'app.html', //指定要生成的文件
            filename: 'app.html', //指定要生成的文件名称,优先级比file高, 两者指定一个就可以,加上hash会每次生成不同的html文件
            template: 'index.html', //需要被打包的模版html
            inject: 'body', //指定脚本插入的标签位置, 可以是head,body等标签
            title: 'webpack is good',
            minify: { //对html文件进行压缩
                removeComments: true, //删除打包的文件内部代码注释
                collapseWhitespace: true, //删除空格
            },
        }),
    ],
    ...
   }
  • clean-webpack-plugin
 作用:  自动清除上一次打包的dist文件

命令:

 npm/cnpm install clean-webpack-plugin --save-dev
//webpack.config.js配置
const path = require('path');
//const CleanWebpackPlugin = require('clean-webpack-plugin'); //旧语法
const {CleanWebpackPlugin} = require("clean-webpack-plugin"); //clean-webpack-plugin3.x版本之后,更新了引入方式

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'js/[name].js',//文件名默认[name].js, 
  },
    plugins: [
        new HtmlWebpackPlugin({
        template: 'index.html' //在打包之后,以.html为模板,把打包生成的js自动引入到这个html文件中
    }),
       // new CleanWebpackPlugin(['dist']), // 在打包之前,可以删除dist文件夹下的所有内容
       new CleanWebpackPlugin() //clean-webpack-plugin3.x版本之后,不需要指定目录删除
    ]
};

  • extract-text-webpack-plugin
 作用: 抽离 css 样式,防止将样式打包在 js 中引起页面样式加载错乱的现象

命令:

 npm/cnpm install extract-text-webpack-plugin@next --save-dev
//webpack.config.js的配置
const ExtractTextPlugin = require('extract-text-webpack-plugin') //引入分离插件
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/, // 正则匹配以.css结尾的文件
        use: ExtractTextPlugin.extract({
          // 相当于回滚,经postcss-loader和css-loader处理过的css最终再经过style-loader处理
          fallback: 'style-loader',
          use: ['css-loader', 'postcss-loader']
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('css/index.css') // 将css分离到/dist文件夹下的css文件夹中的index.css
  ]
}

在其执行npm run build 之后,在dist目录下会自动生成 css目录及其下index.css文件

  • purifycss-webpack、 purify-css、 glob
purifycss-webpack的作用: 消除冗余的css,避免重复代码样式;结合clean-webpack-plugin使用

命令:

 npm/cnpm install purifycss-webpack purify-css glob --save-dev
//webpack.config.js配置
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模块,用于扫描全部html文件中所引用的css

plugins: [
  new PurifyCssWebpack({
    paths: glob.sync(path.join(__dirname, 'src/*.html')) // 同步扫描所有html文件中所引用的css
  })
]
  • plugin对多页面项目的配置支持
  //webpack.config.js多页面配置
   const HtmlWebpackPlugin = require('html-webpack-plugin'); //打包html文件
   module.exports = {
      //context:'' //整个环境的上下文, 也就是项目根目录
       entry: { //入口文件, 在vue-cli中是main.js
          main: './src/index.js',
          app: './src/app.js',
          home: './src/home.js',
          mine: './src/mine.js',
       }, 
      output: {  //webpack如何向外输出
          path: path.resolve(__dirname, 'dist'), //定位,输出文件的目标路径
          filename: 'js/[name].js',//文件名默认[name].js, 可以在前面加上相对路径,生成包裹js文件的文件夹
          //也可用hash chunkhash结合配置. [name]-[hash].js [name]-[chunkhash].js.
        //使用chunkhash,在打包的时候,如果文件无修改,则不会在打包.  等同于版本号,使用用于多页面
          publicPath: 'http://cdn.com/'  //公共路径, 可以理解为绝对地址(域名), 设置publicpath,在打包输出的时候,
                                       //在html中引入的路径会以publicPath+path+filename.js这两个路径拼接后的文件名称引入
    },

    // webpack 中对于plugin的学习
    plugins: [ //数组, 支持生成多页面的html文件
        new HtmlWebpackPlugin({ //将模板的头部和尾部添加css和js模板,dist 目录发布到服务器上,项目包。可以直接上线
            file: 'app.html', //指定要生成的文件
            filename: 'app.html', //指定要生成的文件名称,优先级比file高, 两者指定一个就可以,加上hash会每次生成不同的html文件
            template: 'index.html', //需要被打包的模版html
            inject: 'body', //指定脚本插入的标签位置, 可以是head,body等标签
            title: 'webpack is good',
            minify: { //对html文件进行压缩
                removeComments: true, //删除打包的文件内部代码注释
                collapseWhitespace: true, //删除空格
            },
            chunks: ['main', 'app']
        }),

        new HtmlWebpackPlugin({ //home页面
            filename: 'home.html',
            template: 'home.html',
            inject: true,
            chunks: ['main', 'home'] //chunks属性,指定每一个模版要引入的chunk(js文件),而且是作为数组存在,其内部对象为要引入的chunk名称.
        }),

        new HtmlWebpackPlugin({ //mine页面
            filename: 'mine.html',
            template: 'mine.html',
            inject: true,
            //chunks:['main','home'], excludeChunks和chunks最好两者取其一,互不包含
            excludeChunks: ['home', 'app'], //指定哪些不被引入的chunk(js文件),而剩下的其他chunk,将在该模版进行引入, 它和chunks属性对立,
            //且与优先级高于chunks,也就是说当两者同时存在时,excludeChunks如果包含chunks中的chunk,则该chunk也不会被引入

        })
    ],
    ...
   }

完整项目

基于以上学习过程中,我们已经了解到webpack各项配置的使用,在此我们结合各项功能完整输出一个webpack构建而成的项目结构:

基于原有的基础上,删除dist文件,保留src文件,并在根目录下创建index.html,其内容如下:

<!--index.html代码-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack 入门学习</title>
</head>
<body>
<div id="root"></div>
<div class="container"></div>
<div id="layer"></div>
</body>
</html>

完整的webpack.config.js配置结构

//处理绝对路径
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const ExtractTextPlugin = require('extract-text-webpack-plugin') //引入分离插件
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模块,用于扫描全部html文件中所引用的css

module.exports = {
    //默认是production,打包的文件默认被压缩。开发时可以设置为development,不被压缩
    mode: 'production',
    entry: path.join(__dirname, 'src/index.js'), //入口文件
    output: {
        path: path.resolve(__dirname, 'dist'), //定位,输出文件的目标路径
        filename: 'js/[name].js', //打包后输出文件的文件名称, 文件名默认[name].js, 可以在前面加上相对路径,生成包裹js文件的文件夹
    },
    devServer: {
        hot: true,
        contentBase: './dist', //本地服务器所加载文件的目录
        port: '8088', //设置端口号8088
        inline: true, //文件修改后热更新
        historyApiFallback: true // 不跳转
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: "babel-loader",
                include: path.resolve(__dirname, 'src'),
                exclude: path.resolve(__dirname, "node_modules"), // /node_modules/, //指定排除处理的范围文件,提高打包的速度,可以是正则表达式,还有绝对路径
            }, {
                test: /\.css$/, // 正则匹配以.css结尾的文件
                use: ExtractTextPlugin.extract({
                    // 相当于回滚,经postcss-loader和css-loader处理过的css最终再经过style-loader处理
                    fallback: 'style-loader',
                    use: ['css-loader', 'postcss-loader']
                })
            }, {
                test: /\.(sc|le)ss$/, // 项目中如果有多个ss文件结尾时,正则表达式可以这么使用,最新执行的再前面
                // loader:'style-loader!css-loader!less-loader' 没有postcss-loader可以直接这样使用
                use: [{
                    loader: "less-loader"
                }, {
                    loader: "sass-loader"
                }, {
                    loader: 'postcss-loader', //autoprefixer使用该插件为各浏览器支持的属性加上前缀
                    options: {plugins: [require("autoprefixer")("last 5 versions")]}
                },
                ],
                include: path.resolve(__dirname, 'src'),
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,  //使用file-loader对资源文件的引入,i不区分大小写
                include: path.resolve(__dirname, 'src'),
                use: [
                    //  {
                    //   loader:'file-loader',
                    //   options:{
                    //       name:'assets/[name]-[hash:5].[ext]',  //设置资源图片打包后的地址
                    //   }
                    // },
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 20000,   //限制图片的最大字节
                            name: 'assets/[name]-[hash:5].[ext]',  //设置资源图片打包后的地址
                        }
                    },
                    {
                        loader: 'image-webpack-loader',  //对图片资源进行压缩处理
                    }
                ]
            },
            {
                test: /\.html$/,  //使用html-loader对html模版内容进行引入.
                // include:path.resolve(__dirname, 'src'),
                loader: "html-loader"

            }]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: 'index.html',
            filename: 'index.html',
            inject: true,
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
            }
        }),
        new CleanWebpackPlugin(), // 在打包之前,可以删除dist文件夹下的所有内容
        // new webpack.HotModuleReplacementPlugin()
        new ExtractTextPlugin('css/index.css'), // 将css分离到/dist文件夹下的css文件夹中的index.css
        new PurifyCssWebpack({
            paths: glob.sync(path.join(__dirname, 'src/*.html')) // 同步扫描所有html文件中所引用的css
        })
    ]
}

执行命令npm run devnpm run build,可以看到在项目结构下,自动生成dist文件以及对应的资源文件,同时也可以在页面上看到对应的响应效果,至此webpack的项目就搭建完成了。

本文使用 mdnice 排版