webpack
针对 JS 的模块化打包工具
查看当前版本 webpack --version
安装
webpack 的运行需要依赖 node 环境,因此需要先行安装 node 版本要大于 8.9
node 环境为了可以正常的执行很多代码,会包含各种依赖的包 所以安装node 之后会自动会安装 npm (node package manager) 用来管理 node 上面的各种包
全局安装 3.6.0, 因为 vue cil 2 依赖该版本: npm install webpack@3.6.0 -g
局部安装 : cd 到目录 npm install webpack@3.6.0 --save--dev
为何全局安装后还要局部安装呢:
- 在终端执行 webpack 命令时,使用的都是全局安装的 webpack. 如 cmd 终端或者编辑器自带的终端。
- 在 package.json 文件中定义了 script 时,其中包含了 webpack 命令的话,那么它优先调用的就是局部的 webpack. 局部没有才会调用全局的。 这样在很多人一起做项目的时候只需要用局部的打包,每个人的全局的不一样也不要紧。
- 一个项目往往是特定版本的 webpack, 都使用全局的话 会导致打包出现问题
打包
src: 源码文件夹 (里面有 js; hbs; cjs; sass; image; json)
dist: 打包文件夹 (distribution 发布)(里面有:css; js; image)
一般 src 文件夹中会由一个入口 js, main.js/index.js
这个js 会调用项目里的各种其他 js. 我们会把所有的 js 打包成一个 bundle.js
cd 到文件夹,webpack 打包命令: webpack ./src/main.js ./dist/bundle.js (这里虽然cd 到文件夹了,其实用的还是全局 webpack)
webpack.config.js 文件配置
- 可以把上面的"webpack 打包命令"直接简写成 webpack 然后在该配置文件中设置一些东西来实现 webpack ./src/main.js ./dist/bundle.js
-
const path = require('path'); //动态获取绝对路径需要引入的包(webpack 自带) module.exports = { entry : "./src/main.js", //想要打包的主 js 文件, 项目的入口文件 output: { path: path.resolve(__dirname, 'dist'), //动态的获取绝对路径 __dirname 是 npm 的全局变量 filename: 'bundle.js', //打包之后生成的文件 publicPath: 'dist/' //文件(如图片)打包之后发送到的文件夹 }, module: { rules: [ //配置 各种 loader ] } }
- 执行的时候 直接 cd 到文件夹 执行命令 webpack 即可调用局部 webpack 进行打包工作
package.json 配置
- 它是 npm init 初始化生成的文件
-
{ "name": "tracytestvue", //项目名称 "version": "1.0.0", //项目版本 "description": "Tracy test vue project", //项目描述 "main": "webpack.config.js", //以后讲 "dependencies": { //项目开发时依赖 这里不需要我们自己编辑 npm insert ... 之后会自动添加到这里 "webpack": "^3.6.0" //说明项目安装了本地 webpack }, "devDependencies": {//项目运行时依赖 "webpack-bundle-analyzer": "^4.4.0", //分析哪个 js 文件大,影响页面加载速度的 }, "scripts": { //npm run ... 的映射 "build": "webpack"// npm run build 时候执行 webpack (这里会调用局部的 webpack), "test":"node .build/copy.js" //node 可以抛开浏览器直接执行js 文件,因为服务器没有浏览器, node 的使用使得 js 文件可以成为服务器代码 }, "author": "Tracy", //作者 "license": "ISC"//开源项目的时候才会用的设 }
- 这个文件里是不能写注释的,写注释后就不能正确执行 npm run build 了
loader 的使用
- webpack 本身的功能只能支持 js 模块化的打包。 针对于其他文件类型的模块化打包,我们需要给 webpack 下载不同的 loader.
- loader 涉及的打包领域有: ES6 转 ES5, TypesScript 转换成 ES5, 将 scss/less 转成 css, 将 jsx/vue 文件转成 js 文件
- loader 的使用过程:
步骤1: 通过 npm 安装对应的 loader
步骤2: 在 webpack.config.js 中的 module 关键字下面进行配置 - loader 官网 (org 结尾的网站一般都是非盈利性质的)
loader 中文翻译 - Demo 1 : 将 css 打包进入 bundle.js 文件中
- 入口 main.js 中写入: import style from './css/common.css'
- npm install style-loader --save-dev
npm install --save-dev css-loader - webpack.config.js 配置:
module: { rules: [{ test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" } ] }] }
- 注意: use 数组后面有多个 loader. webpack 是从右向左来读取的, 所以要先写 style-loader 再写 css-loader
css-loader 只负责将 css 文件进行加载,但是并不会将文件加入到 DOM 中,因此页面不会有样式
style-loader 负责将样式加入到 DOM 中, 此时页面才开始有样式 - Tips: 如果打包出错,就查看 package.json 文件 css-loader 和 js-loader 的版本 是不是太高了
在 package.json 文件手动更改版本为 "css-loader": "^3.3.0", "style-loader": "^1.0.0"
之后运行 npm install 会自动添加我们手动修改的版本
再次打包之后错误消失
- 不同的 loader 都需要写在 rules 中, rules 是一个数组。
- Demo 2 : 打包 less, scss, sass 的样式文件
- main.js 引入 less : import less from './css/demo.less'
- npm install --save-dev less-loader less
- webpack.config.js 配置:
{ test: /\.less$/, use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "less-loader" }] }
- less-loader的时候经常会因为版本过高报错, 在 package.json 文件手动更改版本为 4.1.0 之后运行 npm install
- Demo 3: 打包 image 为 Base64 字符串格式 url-loader 功能类似于 file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。
- css 文件中引入 image: background-image: url('../images/view.png');
- npm install --save-dev url-loader
-
{ test: /\.(png|jpg|gif|jpeg)$/, //这里我们自己加上 jpeg use: [ { loader: 'url-loader', options: { limit: 8192 //当加载的图片小于 limit 的 8kb 的时候会将图片编译成 base64 字符串形式 //当图片大于 8kb 的时候需要再下载 file-loader, 这里就不用额外配置什么了 name: 'images/[name].[hash:8].[ext]' //图片大于 limit file-loader 生成的名字 } } ] }
- 图片小于 8kb 打包之后css 文件会变成类似于: background-image:url(data:image/png;base64,iVBORw0KGgoAAAAN...=)
- 当图片大于 设置的 limit 的 8kb 后会报错, 此时我们需要再配置 npm install --save-dev file-loader
file-loader : 将文件发送到输出文件夹,并返回(相对)URL - webpacl.config 的 output 中需要配置图片要发送过去的文件夹 publicPath: 'dist/'
- 其他不用再额外配置了,直接 npm run build 即可
版本过高报错, 在 package.json 文件手动更改版本为 "file-loader": "^4.0.0" - 文件会被改名,成为 32位的 hash 哈希值。发送到 publicPath 的文件夹
但是真实开发中,我们对打包的文件名字是有一定的要求的,此时就要在 option 添加如下选项
name: 'images/[name].[hash:8].[ext]'- images : 文件要打包的文件夹
- [name] : 获取图片原来的名字
- [hash:8]: 放置图片名字重复,依然使用 hash, 保留 8位
- [ext]: 使用原来文件的拓展名
- Demo 4: ES6 转 ES5
- npm
- npm install babel-loader babel-core babel-preset-es2015
这里先不要按照官网的用 babel-preset-env -
{ test: /\.js$/, exclude: /(node_modules|bower_components)/, //排除 node_modules 和 bower_components 里的文件 use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }
- 如果用官网的 babel-preset-env 打包报错后,需要在 webpack.config.js 同级目录创建文件" .babelrc." 然后再进行具体的配置
- 你必须执行 npm install babel-plugin-transform-runtime --save-dev 来把它包含到你的项目中,也要使用 npm install babel-runtime --save-dev 把 babel-runtime 安装为一个依赖。
- Demo 5: 打包 .vue 文件
- npm install vue-loader vue-template-compiler --save-dev
- webpack.config.js 配置:
module: { rules: [{ test: /\.vue$/, use: [ { loader: "vue-loader"} ] }] }
- 此时会报错: vue-loader was used without the corresponding plugin.
因为 vue loader 版本过高, 可以改成 ^13.0.0 (这个^的意思是会安装 13到14之间的一个合适的版本)
重新 npm install - 引入 vue 文件想从 import App from './vue/App.vue' 变成 import App from './vue/App'
去掉后缀名: 在 webpack.config.js 文件中的 resolve 中配置resolve: { extensions:['.js', '.css', '.vue'], }
webpack 中配置 Vue
- 打包 .vue 文件
- npm install vue --save (这里不用 --dev 了,因为 vue 不仅是开发时依赖,而且也是运行时依赖)
默认是安装最新的版本 - 安装好之后直接引入 import Vue from 'vue';
- 使用 vue code 进行开发 并打包,此时浏览器 console 会报错
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build. - Vue 不同构件版本: Vue 在 import 的时候会引用两种文件
- runtime-only: (默认引用) 代码中不可以有任何的 template
- runtime-compiler: 代码中可以有 template, 因为有 compiler 用于编辑 template
- template 也就是组件,我们的代码里有根组件,它也是一个组件,所以用 runtime-only 会报错了
- 解决 runtime-only 报错方案 :
修改 webpack.config.js, 添加如下属性:resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' } }
添加了之后, 在我们 import vue 的时候,就不会默认医用 runtime-only 了, 而是引用 runtime-compiler - vue 终极解决方案
- index.html 文件中
<div id="app"></div>
<script src="./dist/bundle.js"></script> - main.js 文件
import style from './css/common.css' import less from './css/demo.less' // vue import Vue from 'vue'; import App from './vue/App' new Vue({ el: '#app', template: '<App />', components: { App } });
- App.vue 文件: 正常 vue code
- index.html 文件中
plugin 的使用
- plugin 是插件,对现有框架的功能进行扩展
- 使用步骤
- 安装: npm *** (某些插件webpack 已经内置因此才不用安装)
- 配置: webpack.config.js 中的 plugins :[] 中配置插件
- Demo: 添加版权声明
- 安装: 它是 webpack 内置插件所以不用再次安装了
- 配置 const webpack = require ('webpack');
plugins :[ new webpack.BannerPlugin('最终版权归 Tracy 所有') ]
- 打包 html
目前的 index.html 文件还在 dist 文件夹外面,发布的时候还不是很方便。
需要将 html 文件打包到 dist 文件夹中发布的时候就拽这个文件夹即可- 这个插件为我们做的: 自动生成一个index.html文件(可以指定模板来生成)
并且将打包好的 js 文件自动通过 script 标签插入到 index.html 的 body 中 - 安装: npm install html-webpack-plugin --save--div
- 配置: const htmlWebpackPlugin = require('html-webpack-plugin');
new htmlWebpackPlugin({template: 'index.html'}) - 这里的 template 表示根据什么模板来生成 html, 我们目前的 html 是和 webpack.config.js 在同一目录,因此直接写的 index.html 就能找到对应的文件
另外我们需要删除之前在 out put 之中添加的 publicPath 属性,否则插入的js路径会有问题 - error : Cannot read property 'make' of undefined
方法将"html-webpack-plugin"版本由 "^4.2.0"改为 "^3.2.0", - 原来 index.html body 中只写 <div id="app"></div> 即可,引入 js 什么的都不用写了
- 这个插件为我们做的: 自动生成一个index.html文件(可以指定模板来生成)
- 压缩 JS
- 安装: npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
- 配置: const uglifyjsPlugin = request('uglifyjs-webpack-plugin');
new uglifyjsPlugin() - 此时会发现打包报错:报错是因为最新版的uglifyjs-webpack-plugin插件已经不支持es6语法, 所以已经不适合用这个插件了
搭建本地服务器
- 可以实现浏览器自动刷新我们改动之后的效果,每次改动后项目会自动打包到内存中
- 安装: npm install --save-dev webpack-dev-server@2.9.1
- 在 webpack.config.js 中配置
devServer:{ contentBase:'./dist', //为哪一个文件夹提供本地 server 服务 port:端口号, //不设置的话就是8080 inline: true, //页面实时刷新 historyApiFallbacl: 在SPA(单页应用)中,依赖 htmk5 的 history 模式,以后细讲 } - 在 package.json 中的 "scripts" 里设置 "dev": "webpack-dev-server --open" (这里的open 是指执行时候直接打开浏览器)
- 启动项目的时候 npm run dev
webpack 配置文件 config.js 的分离
- 如果把所有的配置都放倒一个 webpack.config.js 文件中,那么在配置很多的时候,是不太合适的.
有些东西是只在测试环境的时候才需要配置的,比如说“搭建本地服务器”
有些东西是只在部署环境的时候才需要配置的,比如说丑化js 和 版权管理等 - 因此我们要把配置文件至少分成三个:
- base.config.js: 测试和部署环境都会用到的配置
- dev.config.js: 测试环境配置
- prod.config.js: 部署环境配置
- 三个文件都放倒 build 文件夹中
base.config.js 中的配置就要改了,因为文件夹换了: path: path.resolve(__dirname, '../dist'), - 安装 npm install webpack-merge --save-dev 用于在 dev.config.js 文件中将它自己和 base.config.js 合并,执行的时候执行一个 dev.config.js 即可
在 dev.config.js 和 prod.config.js 中分别配置 :
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');
module.exports = webpackMerge.merge(baseConfig, {里面放 dev.config.js 或者 prod.config.js 里的 code}) - 删除 webpack.config.js
在 package.json 文件的 "script"中加上 --config ./build/###.config.js 用于覆盖原来默认的 webpack.config.js 文件的操作
"build": "webpack --config ./build/prod.config.js",
"dev": "webpack-dev-server --open --config ./build/dev.config.js"