引言
WebPack的火爆程度已经持续几年了,不管是Vue-Cli还是React-Cli又或者是Angular-Cli都是基于Webpack进行搭建的打包系统,早在几年前就已经出现了一个新的职业WebPack工程师,即便是我不打算从事专业的Webpack,但是我们也决不能仅限于使用Vue-Cli或其它脚手架工具,而且我们再实际开发中都得针对自己的项目二次开发脚手架工具,或自己搭建,因此我们不能只是知其然,也得知其所以然......下面我会把我对webpack的理解根大家分享一下,本文纯属个人理解,有哪里不对的地方还请评论中或关注同学们听我说公众号留言指出,大家一起学习共同进步。
为什么要学Webpack?
- 现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度
- TS 转 JS
- sass 转 css
- ES6 转 ES5
- 这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为WebPack类的工具的出现提供了需求
什么是Webpack?
- WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块它会构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
webpack和gulp及grunt的对比
其实Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,用了gulp或grunt工具之后可以自动替你完成这些任务。
1、 原材料 - *.js
2、加工 - ES6转ES5插件(babel)
3、出厂 - 生成了ES5
定义 第二个任务 - sass转CSS 任务
1、 原材料 - *.scss
2、加工 - scss转css插件
3、出厂 - 生成了浏览器可识别的css
以此类推,根据需求配置任务,按照顺序执行,第三、四、五..... 任务......,可以理解为解放双手的智能化的工作流程。
-
Webpack的工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
![](https://img2018.cnblogs.com/blog/660351/201905/660351-20190515191756799-1667014956.png)
webpack是把整个项目中的所有模块资源,通过入口文件根据import/require分析依赖关系,生成关系树,然后借助于loader和plugins两个核心的属性及其他,转换成浏览器可以识别的JS文件。它不针对流程,而是模块。
特点
Webpack 有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的块。在优化了依赖树后,每一个异步区块都作为一个文件被打包。* Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。* Webpack 有一个智能解析器,几乎可以处理任何第三方库,无论它们的模块形式是 CommonJS、 AMD 还是普通的 JS 文件。甚至在加载依赖的时候,允许使用动态表达式 require(“./templates/” + name + “.jade”)。* Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。* Webpack 使用异步 I/O 和多级缓存提高运行效率,这使得 Webpack 能够以令人难以置信的速度快速增量编译。
核心概念
entry - 入口
-
指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的
entry: { index: './src/index.js' },
output - 出口
-
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为
./dist
。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个output
字段,来配置这些处理过程output: { filename: '[name].bundle.[hash].js', path: path.join(__dirname, 'dist') },
loader
-
loader让 webpack 能够去处理那些非 JavaScript 文件
-
loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理,本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
loader
-
loader让 webpack 能够去处理那些非 JavaScript 文件
-
loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理,本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
module: { rules: [ { test: /.css$/, use: ['style-loader', 'css-loader'] }, { test: /.(png|jsp|gif)/, use: [{ loader: 'url-loader', options: { limit: 1024, outputPath: 'imgs/', publicPath: 'dist/' } }] //或者你可以简写成如下形式: //use: 'url-loader?limit=1024&name=[path][name].[ext]&outputPath=images/&publicPath=dist/', } ] },
plugins - 插件
-
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,
-
想要使用一个插件,你只需要
require()
它,然后把它添加到plugins
数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用new
操作符来创建它的一个实例。
plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', template: './index.html' //以当前目录下的index.html文件为模板生成dist/index.html文件 }), new CleanWebpackPlugin(['dist']) ////传入数组,指定要删除的目录 ]
WebPack是一种模块化管理方案/模块打包工具,在他的眼里就是万物皆模块,可以用loader(加载器/转换器)把任何一个文件资源打包成浏览器认识的JavaScript模块.
实战 - Vue-Cli
安装插件:
1、首先webpack是在node环境下运行的,电脑环境中需要有node和npm,并且node版本必须是v8.5以上的,否则不支持webpack 4。
2、本地创建一个文件夹vue-cli
,在vue-cli
根目录下打开cmd
,然后在小黑窗中输入npm init -y
,生成package.json
文件。
3、安装插件Vue-loader和webpack:
- webpack webpack-cli 本地再安装一次
- vue vue-loader webpack需要读取vue文件并加载成它所认识的js
npm install vue webpack webpack-cli vue-loader
4、安装静态资源插件比如,img、style、css的loader和vue-template-compiler(用来编译vue模板),url-loader封装了file-loader,将我们要求的格式的图片转换成计算机的base64编码:
npm i style-loader css-loader url-loader file-loader vue-template-compiler -D
配置WebPack并打包项目
1、在根目录下创建:src/index.js
、src/App.vue
、webpack.config.js
、index.html
![](https://img2018.cnblogs.com/blog/660351/201905/660351-20190515192121785-1209857422.png)
App.vue
<template> <div> Hello Webpack! </div> </template> <script> </script> <style scoped> </style>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"></div> </body> </html>
index.js
/** @Author:Wyunfei @Date:2019/3/1/18:42 @FileName: index.js */ import Vue from 'vue' import App from './App.vue' new Vue({ el: '#app', components: { App }, template: `<App />` })
webpack.config.js
/** @Author:Wyunfei @Date:2019/3/1/18:44 @FileName: webpack.config.js */ const Path = require('path') const VueLoaderPlugin = require('vue-loader/lib/plugin'); // webpack 4版本之后加的,之前的版本不需要这个 let config = { entry: Path.resolve(__dirname, './src/index.js'), // 以join拼接path的形式配置绝对路径,相对路径打包后找不到会报错 output: { filename: 'vendor.build.js', path: Path.join(__dirname, 'dist') }, module: { rules: [{ test: /.vue$/, loader: 'vue-loader' }, { test: /.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /.(png|jpg|jpeg|gif)$/, use: { loader: 'url-loader', options: { limit: 1024, // 判断图片的大小 如果小于1024就会转换成base64 name: '[name].[ext]' // 输出图片的名字 ext是扩展名 } } }] }, plugins: [ new VueLoaderPlugin() ] }; module.exports = config;
上面配置好了之后还差最后一步,就是用webpack来执行配置跑项目,在scripts里面加上build:
package.json
"build": "webpack --config webpack.config.js"
执行命令npm run build
后会在根目录下看到一个dist/vendor.build.js
,就是我们打包好的文件,这一步就省去了我们很多的http请求,达到更优化的效果。
运行项目
1、现在项目已经打包好了,接下来开始运行我们的项目,先建立一个属于我们的开发模式,这里需要使用webpack-dev-server来启动我们的webpack.config.js,进而运行我们的项目。使用它的东西第一步就是要安装npm i webpack-dev-server,再往scripts里面加上这个"dev": "webpack-dev-server --config webpack.config.js":
![](https://img2018.cnblogs.com/blog/660351/201905/660351-20190515192331956-2142216029.png)
接下来增加一些开发模式需要用到的webpack的配置
2、webpack的编译目标是web项目,所以我们要target: 'web',放在全局的webpack的配置里面
webpack.config.js
3、需要配置一个环境变量来区分我们的生产环境和开发环境,输入dos命令安装npm i cross-env
,在打包和运行之前都加上环境变量标识:
"scripts": { "test": "echo "Error: no test specified" && exit 1", "build": "cross-env NODE_ENV=production webpack --config webpack.config.js", "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js" },
4、再从webpack的配置里加个判断,如果是开发环境,就把我们的webpack服务放进去:
首先用一个变量代表是开发环境:const isDev = process.env.NODE_ENV === 'development';在package.json scripts里面设置的生产和开发环境的环境变量都存在于cross-dev,我们设置脚本的时候启动的环境变量全都存在于process.env里面,这样我们在之后可以随意调用它
然后在最下面给module.exports赋值之前,加个判断:记住安装npm install webpack-dev-server
webpack.config.js
if (isDev) { config.devServer = { port: 8088, // webpack服务需要监听的端口号 host: '0.0.0.0', // 可以通过本机内网ip访问,这样别人也可以访问,手机也可访问,如果设置成localhost则不然 overlay: { errors: true // 这个可有可无,webpack编译出现的错误会出现在网页中,便于更改 } }; } module.exports = config;
5、引入webpack,以便之后用webpack的插件,下面会用到DefinePlugin这个插件(ps:做vue或react的项目必须用到的,这些项目都会根据环境来区分打包)
const Webpack = require('webpack');
6、用法和之前的一样,所有的插件都是需要引入并创建实例这一过程;下面根据之前配置好的环境变量在webpack编译的过程中,对写的js代码都会判断环境,根据不同环境对代码进行打包,代码如下:
plugins: [ new VueLoaderPlugin(), new Webpack.DefinePlugin({ 'process-env': { NODE_ENV: isDev ? '"development"' : '"production"' } }) ]
7、这也是最后一步,我们到现在为止还没有一个网页入口,先安装一个html-webpack-plugin,同样的引入配置好了,运行一下项目就ok了
const HtmlWebpackPlugin = require('html-webpack-plugin'); plugins: [ new VueLoaderPlugin(), new Webpack.DefinePlugin({ 'process-env': { NODE_ENV: isDev ? '"development"' : '"production"' } }), new HtmlWebpackPlugin({ filename: 'index.html', template: './index.html' //以当前目录下的index.html文件为模板生成dist/index.html文件 }) ]
运行结果:
访问结果:
Vue项目开发
1、创建:src/components/index.vue
、src/router/index.js
、src/assets/css/index.css
安装npm install vue-router -D
components/index.vue
<template> <h1> Hello Vue-Router </h1> </template> <script> </script> <style scoped> </style>
assets/css/index.css
/** @Author:Wyunfei @Date:2019/3/1/19:51 @FileName: index */ html,body { width: 100%; height: 100%; background: pink; }
2、路由配置
router/index.js
/** @Author:Wyunfei @Date:2019/3/1/19:36 @FileName: index.js */ import Vue from 'vue' import Router from 'vue-router' import Index from '../components/index.vue' Vue.use(Router) export default new Router({ routes: [ { path: '/', component: Index } ] })
src/index.js
/** @Author:Wyunfei @Date:2019/3/1/18:42 @FileName: index.js */ import Vue from 'vue' import App from './App.vue' import './assets/css/index.css' import router from './router/index.js' new Vue({ el: '#app', router, render: (h) => h(App) })
components/index.vue
<template> <h1> Hello Components </h1> </template> <script> </script> <style scoped> </style>
src/App.vue
<template> <div> Hello Webpack! <router-view /> </div> </template> <script> </script> <style scoped> </style>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> </div> </body> </html>
npm run dev
就可以通过localhost + 端口
在浏览器访问了npm run build
就可以打包生成dist目录了,放到服务器上,上线啦~~