webpack搭建和使用
webpack路线
webpack的意义
- 模块化的思想(模块打包器)
- scss、less、typescript的预处理器以及loader加载工具
webpack的安装
webpack基于node环境, 具体node的安装就不说了, 下面主要是webpack的安装
// 全局安装
npm install -g webpack
// 安装到项目上
npm install --save-dev webpack
webpack的使用
- 新建一个webpack的文件夹
mkdir webpack-demo
cd webpack-demo
npm init
npm install --save-dev webpack webpack-cli
说明: webpack4将webpack的命令都迁移到webpack-cli, 所以如果你用的webpack版本在4.0一下可以省略安装webpack-cli
- 新建文件夹app和public,public放入一个公共的index.html文件, 新建app文件夹的main.js和greeter.js
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack 简单练习</title>
</head>
<body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
main.js
let greeter = require('./greeter.js');
document.querySelector('#root').append(greeter());
greeter.js
module.exports = function() {
let greeter = document.createElement('div');
greeter.innerText = '测试webpack';
return greeter;
};
- 现在我们可以使用webpack命令打包文件
// 全局安装webpack
webpack app/main.js public/bundle.js
// 非全局安装webpack
node_modules/.bin/webpack app/main.js public/bundle.js
- webpack成功之后产生一个bundle.js文件
D:\study\webpack\webpack-demo>webpack
Hash: a891a5964dd833cfdb21
Version: webpack 4.32.2
Time: 97ms
Built at: 2019-05-29 16:20:18
Asset Size Chunks Chunk Names
bundle.js 2.2 KiB 0 [emitted] main
Entrypoint main = bundle.js
[0] ./app/main.js 90 bytes {0} [built]
[1] ./app/greeter.js 136 bytes {0} [built]
- 每次打包命令挺烦, 下面通过配置文件使用webpack,新建webpack.config.js文件
module.exports = {
entry: __dirname + "/app/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"//打包后输出文件的文件名
}
}
- 配置package.json文件
{
"name": "webpack-sample-project",
"version": "1.0.0",
"description": "Sample webpack project",
"scripts": {
"start": "webpack" // 修改的是这里,JSON文件不支持注释,引用时请清除
},
"author": "zhang",
"license": "ISC",
"devDependencies": {
"webpack": "3.10.0"
}
}
- 以后可以使用命令可以直接打包
npm run start 或者 npm start
webpack的配置和强大功能
生成Source Maps(使调试更容易)
开发总是离不开调试,方便的调试能极大的提高开发效率,不过有时候通过打包后的文件,你是不容易找到出错了的地方,对应的你写的代码的位置的,Source Maps就是来帮我们解决这个问题的。
通过简单的配置,webpack就可以在打包时为我们生成的source maps,这为我们提供了一种对应编译文件和源文件的方法,使得编译后的代码可读性更高,也更容易调试。
devtool选项
配置结果
source-map
在一个单独的文件中产生一个完整且功能完全的文件。这个文件具有最好的source map,但是它会减慢打包速度;
cheap-module-source-map
在一个单独的文件中生成一个不带列映射的map,不带列映射提高了打包速度,但是也使得浏览器开发者工具只能对应到具体的行,不能对应到具体的列(符号),会对调试造成不便;
eval-source-map
使用eval打包源文件模块,在同一个文件中生成干净的完整的source map。这个选项可以在不影响构建速度的前提下生成完整的sourcemap,但是对打包后输出的JS文件的执行具有性能和安全的隐患。在开发阶段这是一个非常好的选项,在生产阶段则一定不要启用这个选项;
cheap-module-eval-source-map
这是在打包文件时最快的生成source map的方法,生成的Source Map 会和打包后的JavaScript文件同行显示,没有列映射,和eval-source-map选项具有相似的缺点;
对小到中型的项目中,eval-source-map是一个很好的选项,再次强调你只应该开发阶段使用它,我们继续对上文新建的webpack.config.js
配置eval-source-map,配置完webpack.config.js如下:
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
}
}
使用webpack构建本地服务器
安装npm install --save-dev webpack-dev-server
配置webpack-dev-server到webpack.config.js,如下:
module.exports = {
devtool: 'eval-source-map', // 方便调试
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
// webpack-dev-server 配置本地服务器
devServer: {
contentBase: './public', // 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录
inline: true, // 设置为true,当源文件改变时会自动刷新页面
historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
port: 7010 // 设置默认监听端口,如果省略,默认为”8080“
},
在package.json中的scripts对象中添加如下命令,用以开启本地服务器:
"scripts": {
"start": "webpack",
"server": "webpack-dev-server --open"
},
在项目的根目录下运行npm run server启动项目
webpack的loader处理器
loader处理的问题
- loader是从右向左的取值
- loader 支持链式传递,链中的每个 loader 会将转换应用在已处理过的资源上
- loader 也可以内联显示指定
- loader 可以是同步的,也可以是异步的
- loader 运行在 Node.js 中,并且能够执行任何 Node.js 能做到的操作
- loader 可以通过 options 对象配置
- 除了常见的通过 package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块
- loader 能够产生额外的任意文件
常用的loader
- style-loader 将css添加到DOM的内联样式标签style里
- css-loader 允许将css文件通过require的方式引入,并返回css代码
- less-loader 处理less
- sass-loader 处理sass
- postcss-loader 用postcss来处理CSS
- autoprefixer-loader 处理CSS3属性前缀,已被弃用,建议直接使用postcss
- file-loader 分发文件到output目录并返回相对路径
- url-loader 和file-loader类似,但是当文件小于设定的limit时可以返回一个Data Url
- html-minify-loader 压缩HTML
- babel-loader 用babel来转换ES6文件到ES5
import Styles from 'style-loader!css-loader?modules!./style.css'
use: [
{ loader: 'style-loader' },
{
loader: 'loader-css',
options: {
modules: true,
minimize: true
}
},
{ loader: 'sass-loader' }
]
以babel-loader为例
安装
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
配置webpack.config.js
/**
* __dirname node.js的全局变量,指向当前执行脚本的所在目录
* @type {{entry: string, output: {path: string, filename: string}}}
*/
module.exports = {
devtool: 'eval-source-map', // 方便调试
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
// webpack-dev-server 配置本地服务器
devServer: {
contentBase: './public', // 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录
inline: true, // 设置为true,当源文件改变时会自动刷新页面
historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
port: 7010 // 设置默认监听端口,如果省略,默认为”8080“
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
}
]
}
};
Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个你需要的功能或拓展,你都需要安装单独的包(用得最多的是解析Es6的babel-env-preset包和解析JSX的babel-preset-react包)。
安装 React 和 React-DOM
npm install --save react react-dom
插件的使用
Loaders和Plugins常常被弄混,但是他们其实是完全不同的东西,可以这么来说,loaders是在打包构建过程中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操作单个文件,它直接对整个构建过程其作用。
插件的使用
module.exports = {
...
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('版权所有,翻版必究')
],
};
HtmlWebpackPlugin
这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html。这在每次生成的js文件名称不同时非常有用(比如添加了hash值)。
npm install --save-dev html-webpack-plugin
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/**
* __dirname node.js的全局变量,指向当前执行脚本的所在目录
* @type {{entry: string, output: {path: string, filename: string}}}
*/
module.exports = {
devtool: 'eval-source-map', // 方便调试
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
// webpack-dev-server 配置本地服务器
devServer: {
contentBase: './public', // 默认webpack-dev-server会为根文件夹提供本地服务器,如果想为另外一个目录下的文件提供本地服务器,应该在这里设置其所在目录
inline: true, // 设置为true,当源文件改变时会自动刷新页面
historyApiFallback: true, //在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
port: 7010 // 设置默认监听端口,如果省略,默认为”8080“
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
modules: true, // 指定启用css modules
localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的类名格式
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: '初始化webpack',
template: __dirname + '/app/index.tmpl.html'
})
]
};
打包
npm run server
Hot Module Replacement
Hot Module Replacement(HMR)也是webpack里很有用的一个插件,它允许你在修改组件代码后,自动刷新实时预览修改后的效果。
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack",
"server": "webpack-dev-server --open --hot"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^9.5.1",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.8",
"html-webpack-plugin": "^3.2.0",
"postcss-loader": "^3.0.0",
"style-loader": "^0.23.1",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.4.1"
},
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}