Webpack

作者: 想吃热干面了 | 来源:发表于2020-09-29 13:56 被阅读0次

一、什么是webpack

官方解释

从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具
上述解释,核心就是 模块 和 打包。

前端模块化:webpack中模块化的概念

在学习模块化时,我们了解了一些

目前使用的前端模块化的方案:AMD、CMD、CommonJS、ES6。但是除了ES6浏览器有支持可以直接使用外,其他的必须借助于其他工具,支持我们进行模块化开发,并且通过模块化开发完成了项目,还需要处理模块间的各种依赖,将其进行整合打包。
webpack其中一个核心就是让我们可以进行模块化开发,并且帮助我们处理模块间的依赖关系。
这就是webpack中模块化的概念。
注:webpack中js、css、图片、json文件都可以当作模块使用。

打包如何理解

就是将webpack中的各种资源模块化进行打包合并成一个或多个包(Bundle)。
在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作

webpack打包与grunt/gulp的区别

grunt/gulp

grunt/gulp的核心是Task:通过配置一系列的Task,定义task要处理的事务(ES6、ts转化;图片压缩等),之后依次执行这些task,让整个流程自动化。所以grunt/gulp也被称为前端自动化任务管理工具。

grunt/gulp适用于工程模块依赖非常简单(甚至没有用到模块化的概念)的只需进行简单的合并、压缩的场合。

webpack与grunt/gulp的不同
  • grunt/gulp更加强调前端流程的自动化,模块化不是它的核心。
  • webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是它附带的功能。

二、webpack安装

webpack的正常运行是依赖于node环境的。node环境依赖各种包,npm是node管理包的工具。

三、webpack的基本使用

1.项目结构:

创建项目时,有两个文件夹,一个是dist文件夹,是打包,发布使用的。一个是src文件夹,主要编码开发用。

2.js文件的打包

  • 实际开发中,如果直接在index.html中引入使用模块化的方式进行开发的js文件,是不可以的。因为浏览器不识别其中的模块化代码。并且许多这样的js,一个个引用非常麻烦,且不利于管理。
  • 这时就可以使用webpack打包,webpack是一个模块化的打包工具。它可以处理所有模块间的关系,且将多个js文件打包到一个js文件中,这样直接在index.html中直接引用一个js文件就可以了。
  • webpack4打包指令: 加了 -o
    webpack .\src\main.js -o .\dist\bundle.js --mode development
    webpack '要打包的文件路径' -o '打包保存文件路径' --mode development (模式 开发模式)

3.webpack.config.js和package.json的配置

配置webpack.config.js可以简化打包命令
const path = require('path')
module.exports = {
  mode : 'development',
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
}
package.json
{
  "name": "meetwebpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.6.0"
  }
}
本地安装webpack
npm install webpack@3.6.0 --save-dev
在配置完成后,我们可以在终端中执行“webpack”命令就可以打包了。需要注意的是,在终端中执行webpack命令,执行的都是全局安装的webpack。所以可以在package.json中配置脚本,使得优先寻找本地的webpack。
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
配置后,执行下面命令就可以打包了
  npm run build

四、loader

loader是webpack中一个非常核心的概念

当我们需要在webpack中加载css、图片,高阶ES6转成ES5代码,TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等时,就需要给webpack扩展对应的loader。
loader使用过程:
  • 通过npm安装loader
  • 在webpack.config.js中的modules关键字下进行配置。

1.css文件打包

  • 安装css-loader和style-loader
    //css-loader:只负责将css文件进行加载
    //style-loader:负责将样式添加到DOM中
    npm install --save-dev css-loader 
    npm install style-loader --save-dev
    
  • 在webpack.config.js中配置
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [ 'style-loader', 'css-loader' ]
          }
        ]
      }
    }
    
  • 在mian.js中导入依赖
    require('./css/normal.css')
    

2.less文件的处理

  • 安装less-loader
    npm install --save-dev less-loader@4.1.0 less@3.9.0
    
  • 在webpack.config.js中配置,直接写在上面的数组中即可
    {
      test: /\.less$/,
      use: [{
        loader: "style-loader" // creates style nodes from JS strings
      }, {
        loader: "css-loader" // translates CSS into CommonJS
      }, {
        loader: "less-loader" // compiles Less to CSS
      }]
    }
    
  • 在mian.js中导入依赖
    require('./css/speical.less')
    

3.图片文件处理

  • 安装css-loader和style-loader
    npm install --save-dev url-loader@1.1.2
    
  • 在webpack.config.js中配置
    {
      test: /\.(png|jpg|gif|jpeg)$/,
      use: [
        {
          loader: 'url-loader',
          options: {       
            limit: 10000,
            name: 'img/[name].[hash:8].[ext]'
          }
        }
      ]
    }
    
limit参数:大小限制
当加载的图片,小于limit时,会将图片编译成base64字符串形式
当加载的图片,大于limit时,需要使用file-loader模块进行加载 且当成模块 需要打包
安装file-loader,file-loader不需要配置,安装即可
  npm install file-loader@1.1.11 --save-dev
name参数:图片打包后默认名字是一串hash值,并且是在dist文件夹下,不利于管理查看。这时我们可以使用name属性,对其重新命名,并且放到统一的文件夹中管理。
 name: 'img/[name].[hash:8].[ext]'
 img文件夹;[name]表示原来的名字;(.)用来拼接;[hash:8]表示生成8位hash值;[ext]表示图片格式。

4.ES6语法处理

目前,有一些浏览器对一些ES6语法还不支持,所以打包js文件时可能需要将ES6语法转成ES5。

  • 安装css-loader和style-loader
    npm install --save-dev babel-loader@7.1.5 babel-core@6.26.3 babel-preset-es2015@6.24.1
    
  • 在webpack.config.js中配置
    {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['es2015']
        }
      }
    }
    
presets对应一个文件,没有这个文件时,就先使用es2015

五、webpack配置vue

1.安装vue.js(需要将vue当作一个模块,所以通过npm安装)

  npm install vue@2.5.21 --save

2.引入依赖

  import Vue from 'vue'

3.简单尝试

<div id="app">
  <h2>{{message}}</h2>
</div>

import Vue from 'vue';

const app = new Vue({
  el: '#app',
  data: {
    message: 'Hello webpack'
  }
});

4.但是打包运行后会报错

webpack-vue.png

原因:我们只是安装了runtime-only,不允许有template,代码中div会被当作一个template


vue.png

5.解决方法:在webpack.config.js中添加配置,改变指定的vue文件

  resolve: {
    //alias:别名
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  }

6.el和template的区别

真实项目中,我们为了不频繁更改index.html的代码的,所以vue显示的内容可以写在vue实例中的template属性。
  new Vue({
    el: '#app',
    template: `
    <div>
    <h2>{{message}}</h2>
    <button @click="btnClick"></button>
    <h2>{{name}}</h2>
    </div> 
    `,
  data: {
      message: 'Hello webpack',
      name: 'codeWhy'
  },
  methods: {
    btnClick() {

    }
  }
});

在运行后,template属性的内容会替换掉index.html中id为app的div

7.vue的终极使用方案(vue文件封装处理)

  • 上面的代码是将vue显示的内容可以写在vue实例中的template属性,但是这样也还不好,还需要进一步的封装。
  • webpack中核心是什么?模块化!既然这样,是不是可以将vue实例中的内容分割出去,当成一个模块。
  • 在创建文件时,可以看到有vue component的选项,这个就是工具提供的vue模版
vue模版 (2).png
  • 接着就可以将显示的内容对应填写,默认导出了
    <template>
      <div>
        <h2 class="title">{{message}}</h2>
        <button @click="btnClick">按钮</button>
        <h2>{{name}}</h2>
        <Cpn></Cpn>
      </div>
    </template>
    
    <script>
      import Cpn from './Cpn.vue'
      //已经默认导出
      export default {
        name: "app",
        components: {
          Cpn
        },
        data() {
          return {
            message: 'Hello webpack',
            name: 'codeWhy'
          }
        },
        methods: {
          btnClick() {
          }
        }
     }
    </script>
    //这里还可以写css样式
    <style scoped>
      .title {
        color: green;
      }
    </style>
    
  • 在main.js中导入使用即可
    import App from './vue/App.vue'
    
    new Vue({
      el: '#app',
      template: `<App/>`,
      components: {
        App
      }
    });
    
  • 注意:在使用时,需要vue-loader
    npm install vue-loader@15.4.2 vue-template-compiler@2.5.21 --save-dev
    
  • 配置
    {
      test: /\.vue$/,
      use: ['vue-loader']
    }
    

六、认识plugin

plugin是什么:

plugin是插件的意思,通畅用于对某个现有的架构进行扩展

loader和plugin的区别:

loader主要用于转换某些类型的模块,是一个转换器。
plugin是插件,对webpack本身的扩展,是一个扩展器。

使用过程:

1).通过npm安装
2).在webpack.config.js中的plugins中配置

各种plugin

①添加版权的plugin
作用:打包后的文件上方标识代码版权所有者
  const webpack = require('webpack');

  module.exports = {
    plugins: [
        new webpack.BannerPlugin('最终版权归国家所有')
    ]
  }
②打包html的plugin

目前,我们的index.html文件是放在根目录下的。在我们真是发布项目时的dist文件夹中并没有index.html。所以我们需要将index.html打包到dist文件夹中。这时就可以使用HtmlWebpackPlugin插件。

作用:

自动生成一个index.html文件(可以指定模版)
将打包的js文件自动通过script标签插入到body中

安装HtmlWebpackPlugin插件
  npm install html-webpack-plugin@3.2.0 --save-dev
配置
    plugins: [
        new HtmlWebpackPlugin({
          template: 'index.html'
        }),
    ]

③js压缩的plugin

作用:将打包的js压缩
安装uglifyjs-webpack-plugin插件
        npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
配置:开发时不需要,不好调试
    plugins: [
        new UglifyjsWebpackPlugin(),
    ]

七、webpack-dev-server搭建本地服务器(打包时不需要)

存在问题:
在开发中,我们不可能每修改次代码就从新打包来看修改后的结果,这样从磁盘中读取信息影响效率。
解决方法:
 webpack提供了一个可选的本地开发服务器,基于node.js搭建,内部是express框架,使浏览器可以自动刷新显示我们修改后结果。从而使得我们可以在确认无误后只打一次包。
它是一个单独的模块,使用前也需要安装
  npm install --save-dev webpack-dev-server@2.9.1
配置webpack.config.js
module.exports = {
    devServer: {        
      contentBase: './dist',(为那一个文件夹提供本地服务,默认根文件,我们需填上打包指定文件夹)
      inline: true,(页面实时刷新)
      port(可以指定端口号,默认8080)          
    }
}
还需在package.json文件中配置启动脚本
     "dev": "webpack-dev-server"
配置后在终端中使用下面的命令即可开启服务
     npm run dev
补充:

配置脚本还可以写成("dev": "webpack-dev-server --open"),添加--open后缀,意思是可以在启动服务时,自动打开网页。

八、配置文件的分离

在webpack.config.js配置文件中,有些是开发时的配置(webpack-dev-server),有的是编译时的配置(uglifyjs-webpack-plugin)。如果都放在一起的话不利于管理。所以我们接下来可以将配置文件进行分离操作。

需要安装webpack-merge:可以对配置文件进行合并
  npm install webpack-merge@4.1.5 --save-dev
要达成下图中的效果:将一个文件分成三个文件
配置分离.png
原文件:webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
  {
    test: /\.less$/,
    use: [{
      loader: "style-loader" // creates style nodes from JS strings
    }, {
      loader: "css-loader" // translates CSS into CommonJS
    }, {
      loader: "less-loader" // compiles Less to CSS
    }]
  },
  {
    test: /\.(png|jpg|gif|jpeg)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'img/[name].[hash:8].[ext]'
        }
      }
    ]
  },
  {
    test: /\.vue$/,
    use: ['vue-loader']
  }
]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  plugins: [
      new webpack.BannerPlugin('最终版权归国家所有'),
      new HtmlWebpackPlugin({
        template: 'index.html'
      }),
      new UglifyjsWebpackPlugin(),
  ],
  devServer: {
    contentBase: './dist',
    inline: true
  }
}
将开发时需要的配置抽出:使用webpackMerge可以和公共的配置合并 dev.config.js
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');

module.exports = webpackMerge(baseConfig, {
  devServer: {
    contentBase: './dist',
    inline: true
  }
})
将打包时需要的配置抽出:使用webpackMerge可以和公共的配置合并 prod.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');

module.exports = webpackMerge(baseConfig, {
  plugins: [
    new UglifyjsWebpackPlugin(),
  ],
})
整理公共配置:base.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: 'bundle.js',
},
module: {
rules: [
  {
    test: /\.css$/,
    use: [ 'style-loader', 'css-loader' ]
  },
  {
    test: /\.less$/,
    use: [{
      loader: "style-loader" // creates style nodes from JS strings
    }, {
      loader: "css-loader" // translates CSS into CommonJS
    }, {
      loader: "less-loader" // compiles Less to CSS
    }]
  },
  {
    test: /\.(png|jpg|gif|jpeg)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
              limit: 10000,
              name: 'img/[name].[hash:8].[ext]'
            }
          }
         ]
      },
      {
        test: /\.vue$/,
      use: ['vue-loader']
      }
    ]
  },
  resolve: {
    //alias:别名
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  plugins: [
    new webpack.BannerPlugin('最终版权归国家所有'),
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
  ],
}

相关文章

网友评论

      本文标题:Webpack

      本文链接:https://www.haomeiwen.com/subject/tmkjsktx.html