在终端执行npm init
命令生成package.jsoncss
该命令会询问项目名称、描述、做者、入口、测试命令等等信息(能够无论, 直接一路回车)html
本地安装 eslintnode
npm install eslint --save-dev
复制代码
eslint官方提供了3种预安装包, 使用eslint-config-standardreact
npm install eslint-config-standard eslint-plugin-standard eslint-plugin-promise -D
复制代码
初始化eslint文件webpack
eslint --init
复制代码
执行eslint --init命令后, 会提示一系列问题如图,而后在根目录下生成一文件.eslintrc.js, 修改extends为standardios
// .eslintrc.js
module.exports = {
"env": {
"browser": true,
"commonjs": true
},
"extends": "standard"
};
复制代码
由于webpack4.x版本以后 webpack模块一部分功能分到webpack.cli模块, 因此二者都须要安装,具体命令以下web
npm install webpack webpack-cli --global
复制代码
npm install webpack webpack-cli --save-dev
复制代码
上述命令可采用简写,install可简写为i,--global可简写为-g,--save-dev可简写为-D(这个命令是用于把配置添加到package.json的开发环境配置列表中,后面会提到),--save可简写为-S正则表达式
npm i webpack -g //这是安装全局webpack命令
npm i webpack webpack-cli -D //这是安装本地项目模块
复制代码
hello.js中 导出一个模块npm
// hello.js
module.exports = function() {
let hello = document.createElement('div');
hello.innerHTML = "Hello World!";
return hello;
};
复制代码
index.js中引入该模块json
const hello = require('./hello')
document.getElementById('root').appendChild(hello)
复制代码
咱们打包时就只需把index.js模块打包成bundle.js,而后供index.html引用便可,这就是最简单的webpack打包原理
webpack全局安装的状况下npm install webpack webpack-cli -g
在终端执行如下打包命令
webpack src/index.js --output dist/bundle.js
复制代码
output能够简写o
新建webpack.config.js, 简单的配置入口, 出口配置
注:webpack.config.js文件中的__dirname是node.js中的一个全局变量,它指向当前执行脚本所在的目录 即D:\GitLab\webpack4
注:path.join的功能是拼接路径片断。
有了这个配置文件,咱们只需在终端中运行webpack命令就可进行打包,这条命令会自动引用webpack.config.js文件中的配置选项,示例以下:
![]()
{
"name": "webpack4",
"version": "1.0.0",
"description": "webpack4尝鲜",
"main": "index.js",
"scripts": {
"start": "webpack",
"test": "npm run test"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.23.1",
"webpack-cli": "^3.1.2"
}
}
复制代码
咱们就能够在终端中直接执行npm start命令来进行打包,start命令比较特殊,能够直接npm加上start就能够执行,若是咱们想起其余的名称,如build时,就须要使用npm run加上build,即npm run build
命令。 如今咱们执行npm start命令
Webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js构建,它是一个单独的组件,在webpack中进行配置以前须要单独安装它做为项目依赖
安装命令:
npm i webpack-dev-server -D
- contentBase :设置服务器所读取文件的目录,当前咱们设置为"./dist"
- port :设置端口号,若是省略,默认为8080
- inline :设置为true,当源文件改变时会自动刷新页面
- historyApiFallback :设置为true,全部的跳转将指向index.html
// 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: {
contentBase: './dist', // 本地服务器所加载文件的入口
port: '8080', // 端口号8080
inline: true, // 修改源码文件后实时刷新
historyApiFallback: true // 不跳转
}
}
复制代码
在package.json 文件配置启动服务器命令webpack-dev-server --open
// package.json
{
...
"scripts": {
"build": "webpack",
"dev": "webpack-dev-server --open",
"test": "npm run test"
},
...
}
复制代码
咱们把start命令名称改成了build,这样比较语义化,平时的脚手架也多数采用这个名称,咱们用dev(development的缩写,意指开发环境)来启动本地服务器,webpack-dev-server就是启动服务器的命令,--open是用于启动完服务器后自动打开浏览器,这时候咱们自定义命令方式的便捷性就体现出来了,能够多个命令集成在一块儿运行,即咱们定义了一个dev命令名称就能够同时运行了webpack-dev-server和--open两个命令
做为开发,代码调试固然少不了,那么问题来了,通过打包后的文件,你是不容易找到出错的地方的,Source Map就是用来解决这个问题的 经过以下配置,咱们会在打包时生成对应于打包文件的.map文件,使得编译后的代码可读性更高,更易于调试。
// 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: {
contentBase: './', // 本地服务器所加载文件的入口
port: '8080', // 设置端口号,若是省略,默认为8080
inline: true, // 设置为true,当源文件改变时会自动刷新页面
historyApiFallback: false // 设置为true,全部的跳转将指向index.html
},
devtool: 'source-map' // 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
}
复制代码
配置好后,咱们再次运行npm run build进行打包,这时咱们会发如今dist文件夹中多出了一个bundle.js.map文件 若是咱们的代码有bug,在浏览器的调试工具中会提示错误出现的位置,这就是devtool: 'source-map'配置项的做用。
loaders是webpack最强大的功能之一,经过不一样的loader,webpack有能力调用外部的脚本或工具,实现对不一样格式的文件的处理,例如把scss转为css,将ES6六、ES7等语法转化为当前浏览器能识别的语法,将JSX转化为js等多项功能。
Loaders须要单独安装而且须要在webpack.config.js中的modules配置项下进行配置,Loaders的配置包括如下几方面:
- test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
- loader:loader的名称(必须)
- include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选);
- options:为loaders提供额外的设置选项(可选)
若是咱们要加载一个css文件,须要安装配置style-loader和css-loader:
安装css-loader与其依赖:
npm i style-loader css-loader -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: {
contentBase: './', // 本地服务器所加载文件的入口
port: '8080', // 设置端口号,若是省略,默认为8080
inline: true, // 设置为true,当源文件改变时会自动刷新页面
historyApiFallback: false // 设置为true,全部的跳转将指向index.html
},
devtool: 'source-map', // 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
module: {
rules: [
{
test: /\.css$/, // 正则匹配以.css结尾的文件
use: ['style-loader', 'css-loader'] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
}
]
}
}
复制代码
在src文件夹下新建css文件夹,在css文件夹下新建index.css文件 而且在index.js中引入
import './css/index.css'
const hello = require('./hello')
document.getElementById('root').appendChild(hello)
复制代码
安装:
npm i sass-loader node-sass -D // 由于sass-loader依赖于node-sass,因此还要安装node-sass
复制代码
配置SASS的rules
// webpack.config.js
const path = require('path')
module.exports = {
...
module: {
rules: [
{
test: /\.css$/, // 正则匹配以.css结尾的文件
use: ['style-loader', 'css-loader'] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
},
{
test: /\.(scss|sass)$/, // 正则匹配以.scss和.sass结尾的文件
use: ['style-loader', 'css-loader', 'sass-loader'] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
}
]
}
}
复制代码
css文件夹下新建red.scss文件
$--red-color: red;
body{
color: $--red-color;
}
复制代码
index.js中引入red.scss
import './css/red.scss'
import './css/index.css'
const hello = require('./hello')
document.getElementById('root').appendChild(hello)
复制代码
Babel 是一个 JavaScript 编译器 Babel 是一个工具链,主要用于在旧的浏览器或环境中将 ECMAScript 2015+ 代码转换为向后兼容版本(ES六、ES七、ES8...)的 JavaScript 代码。如下是Babel 能够为你作的主要事情
- (1)、转换语法
- (2)、Polyfill 实现目标环境中缺乏的功能 (经过 @babel/polyfill)
- (3)、源代码转换 (codemods)
- (4)、基于JavaScript进行拓展的语言, 例如JSX
Babel实际上是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack能够把其不一样的包整合在一块儿使用,对于每个你须要的功能或拓展,你都须要安装单独的包(用得最多的是解析ES6的babel-preset-env包和解析JSX的babel-preset-react包)。
npm install -D babel-loader @babel/core @babel/preset-env // babel-preset-env的env表示是对当前环境的预处理,而不是像之前使用babel-preset-es2015只能针对某个环境
复制代码
const path = require('path')
module.exports = {
...
module: {
rules: [
...
{
test: /\.(js|jsx)$/,
use: { // 注意use选择若是有多项配置,可写成这种对象形式
loader: 'babel-loader'
// options: { // 后续Babel配置会单独提取到.babelrc文件中
// presets: [ '@babel/preset-env' ] // 支持最新JS语法(ES六、ES七、ES8。。。)
// }
},
exclude: /node_modules/ // 排除匹配node_modules模块
}
]
}
}
复制代码
插件(Plugins)是用来拓展Webpack功能的,它们会在整个构建过程当中生效,执行相关的任务。
Loaders和Plugins经常被弄混,可是他们实际上是彻底不一样的东西,能够这么来讲,loaders是在打包构建过程当中用来处理源文件的(JSX,Scss,Less..),一次处理一个,插件并不直接操做单个文件,它直接对整个构建过程其做用。
使用某个插件,须要经过npm进行安装,而后在webpack.config.js配置文件的plugins(是一个数组)配置项中添加该插件的实例,下面咱们先来使用一个简单的版权声明插件.
// webpack.config.js
...
module.exports = {
...
plugins: [
new webpack.BannerPlugins('版权全部,翻版必究') // new一个插件的实例
]
}
复制代码
新建.babelrc文件, 将Babel配置收取至.babelrc文件中
{
"presets": [ "@babel/preset-env" ]
}
复制代码
咱们都是使用的模板index.html, 那么怎么自动引入打包生成以后的JS文件?HtmlWebpackPlugin插件就是用来解决这个问题的
安装该插件npm i html-webpack-plugin -D
在src文件夹下新建index.html的文件模板(固然这个是可选的,由于就算不设置模板,HtmlWebpackPlugin插件也会生成默认html文件,这里咱们设置模块会让咱们的开发更加灵活),以下:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
复制代码
webpack.config.js中咱们引入了HtmlWebpackPlugin插件,并配置了引用了咱们设置的模板,以下:
// webpack.config.js
const path = require('path') // 路径处理模块
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
....
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/index.html') // new一个这个插件的实例,并传入相关的参数
})
]
}
复制代码
你可能已经注意到,在咱们删掉/dist文件夹以前,因为前面的代码示例遗留,致使咱们的/dist文件夹比较杂乱。webpack会生成文件,而后将这些文件放置在/dist文件夹中,可是webpack没法追踪到哪些文件是实际在项目中用到的。
一般,在每次构建前清理/dist文件夹,是比较推荐的作法,所以只会生成用到的文件,这时候就用到CleanWebpackPlugin插件了。 安装:
npm i clean-webpack-plugin -D
// webpack.config.js
const path = require('path') // 路径处理模块
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/src/index.template.html') // new一个这个插件的实例,并传入相关的参数
}),
new ClearWebpackPlugin(['dist']) // 清理所要清理的文件夾名称
]
}
复制代码
插件的使用方法都是同样的,首先引入,而后new一个实例,实例可传入参数。 如今咱们运行npm run build后就会发现,webpack会先将/dist文件夹删除,而后再生产新的/dist文件夹。
HotModuleReplacementPlugin(HMR)是一个很实用的插件,能够在咱们修改代码后自动刷新预览效果。
方法:
- (1):devServer配置项中添加hot: true参数。
- (2):由于HotModuleReplacementPlugin是webpack模块自带的,因此引入webpack后,在plugins配置项中直接使用便可。
// webpack.config.js
const path = require('path') // 路径处理模块
const webpack = require('webpack') // 这个插件不须要安装,是基于webpack的,须要引入webpack模块
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
...
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/src/index.template.html') // new一个这个插件的实例,并传入相关的参数
}),
new ClearWebpackPlugin(['dist']), // 清理所要清理的文件夾名称
new webpack.HotModuleReplacementPlugin() // 热更新插件
]
}
复制代码
此时咱们从新启动项目npm run dev后,修改hello.js的内容,会发现浏览器预览效果会自动刷新(也许反应会比较慢,由于咱们使用了source-map和其余配置的影响,后面代码分离的时候咱们再处理)。
在当前的开发环境都是提倡模块化,webpack天然不例外,咱们前面的webpack.config.js配置文件,其实也没配置多少东西就这么多了,要是之后增长了更多配置,岂不是看得眼花缭乱,因此最好的方法就是把它拆分,方便管理:
- 根目录下新建webpack.common.js(公共配置文件)、webpack.dev.js(开发环境配置文件)、webpack.prod.js(生产环境配置文件)
安装一个合并模块插件webpack-merge
npm i webpack-merge -D
复制代码
- 拆分webpack.config.js。 删除webpack.config.js。具体实现以下
// webpack.common.js
const path = require('path') // 路径处理模块
const webpack = require('webpack') // 这个插件不须要安装,是基于webpack的,须要引入webpack模块
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包后的文件存放的地方
filename: 'bundle.js' // 打包后输出文件的文件名
},
module: {
rules: [
{
test: /\.css$/, // 正则匹配以.css结尾的文件
use: ['style-loader', 'css-loader'] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
},
{
test: /\.(scss|sass)$/, // 正则匹配以.scss和.sass结尾的文件
use: ['style-loader', 'css-loader', 'sass-loader'] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
},
{
test: /\.(js|jsx)$/,
use: { // 注意use选择若是有多项配置,可写成这种对象形式
loader: 'babel-loader'
// options: { // 后续Babel配置会单独提取到.babelrc文件中
// presets: [ 'env' ] // 支持最新JS语法(ES六、ES七、ES8。。。)
// }
},
exclude: /node_modules/ // 排除匹配node_modules模块
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, '/src/index.template.html') // new一个这个插件的实例,并传入相关的参数
}),
new webpack.HotModuleReplacementPlugin() // 热更新插件
]
}
复制代码
// webpack.prod.js
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
const merge = require('webpack-merge')
const common = require('./webpack.common')
module.exports = merge(common, {
devtool: 'source-map', // 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
plugins: [
new ClearWebpackPlugin(['dist']) // 清理所要清理的文件夾名称
]
})
复制代码
// webpack.dev.js
const merge = require('webpack-merge')
const common = require('./webpack.common')
module.exports = merge(common, {
// 本地服务器配置
devServer: {
contentBase: './', // 本地服务器所加载文件的入口
port: '8080', // 设置端口号,若是省略,默认为8080
inline: true, // 设置为true,当源文件改变时会自动刷新页面
historyApiFallback: false, // 设置为true,全部的跳转将指向index.html
hot: true // 热加载
}
})
复制代码
- 设置package.json的scripts命令:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.prod.js",
"dev": "webpack-dev-server --open --config src/webpack.dev.js",
"test": "npm run test"
},
...
}
复制代码
咱们把build命令改成了webpack --config webpack.prod.js,意思是把打包配置指向webpack.prod.js配置文件,而以前咱们只须要使用一个webpack命令为何就能够运行了?由于webpack命令是默认指向webpack.config.js这个文件名称了,如今咱们把文件名称改了,因此就须要自定义指向新的文件,dev命令中的指令也同理。 而后咱们运行npm run build和npm run dev,效果应该和咱们分离代码前是同样的。
注:说道package.json文件,顺便就多提几句,由于也许有些朋友可能对咱们安装模块时加的-D、-S或-g命令存在一些疑惑,由于不知道何时加什么尾缀。 其实这个package.json文件是用于咱们安装依赖的,能够把它当成一份依赖安装说明表,就是若是咱们把项目上传或者发给其余的开发同事,确定不会把/node_modules文件夹也发送过去,由于这太大了,不现实也不必。 开发同事只须要有这份package.json文件,而后npm install就能够把咱们所须要的依赖都安装下来,但前提是package.json文件上有记录,这就是安装模块时加上-D,-S命令的缘由。 -D的全称是--save-dev指开发环境时须要用到的依赖,会记录在package.json文件中的devDependencies选项中,而-S是--save是指生产环境也就是上线环境中须要用到的依赖,会记录在package.json文件中的dependencies选项中,-g的全称是--global指安装全局命令,就是咱们在本电脑的任何项目中都能使用到的命令,好比安装cnpm这个淘宝镜像命令就会用到-g命令。 因此咱们在安装模块时必定不要忘了加上对应的尾缀命令,让咱们的模块有迹可循,不然其余的开发同事接手你的项目的话,会不会下班后(放学后)在门口等你就不知道了。
平时咱们写css时,一些属性须要手动加上前缀,好比-webkit-border-radius: 10px;,在webpack中咱们能不能让它自动加上呢?那是必须的,首先确定得安装模块了:
npm i postcss-loader autoprefixer -D
复制代码
安装好这两个模块后,在项目根目录下新建postcss.config.js文件:
module.exports = {
plugins: [
require('autoprefixer') // 引用autoprefixer模块
]
}
复制代码
index.css中增长如下样式
body {
background: gray;
}
#root div{
width: 200px;
margin-top: 50px;
transform: rotate(45deg); /* 这个属性会产生前缀 */
}
复制代码
修改webpack.common.js文件中的css-loader配置:
// webpack.common.js
const path = require('path') // 路径处理模块
const webpack = require('webpack') // 这个插件不须要安装,是基于webpack的,须要引入webpack模块
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包后的文件存放的地方
filename: 'bundle.js' // 打包后输出文件的文件名
},
module: {
rules: [
{
test: /\.css$/, // 正则匹配以.css结尾的文件
use: [
{ loader: 'style-loader' }, // 这里采用的是对象配置loader的写法
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }// 使用postcss-loader
] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
},
...
]
}
}
复制代码
而后咱们运行npm run dev后css样式中会自动添加前缀
虽然webpack的理念是把css、js全都打包到一个文件里,但要是咱们想把css分离出来该怎么作呢?
npm i extract-text-webpack-plugin@next -D // 加上@next是为了安装最新的,不然会出错
复制代码
安装完以上插件后在webpack.common.js文件中引入并使用该插件:
// webpack.common.js
const path = require('path') // 路径处理模块
const webpack = require('webpack') // 这个插件不须要安装,是基于webpack的,须要引入webpack模块
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入HtmlWebpackPlugin插件
const ExtractTextPlugin = require('extract-text-webpack-plugin') // 引入分离插件
module.exports = {
entry: path.join(__dirname, '/src/index.js'), // 入口文件
output: {
path: path.join(__dirname, '/dist'), // 打包后的文件存放的地方
filename: 'bundle.js' // 打包后输出文件的文件名
},
module: {
rules: [
{
test: /\.css$/, // 正则匹配以.css结尾的文件
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }// 使用postcss-loader
] // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
})
},
...
]
},
plugins: [
...
new ExtractTextPlugin('css/index.css') // 将css分离到/dist文件夹下的css文件夹中的index.css
]
}
复制代码
有时候咱们css写得多了,可能会不自觉的写重复了一些样式,这就形成了多余的代码,上线前又忘了检查,对于这方面,咱们应该尽可能去优化它,webpack就有这个功能。
npm i purifycss-webpack purify-css glob -D
复制代码
安装完上述三个模块后,由于正常来讲是在生产环境中优化代码,因此咱们应该是在webpack.prod.js文件中进行配置,引入clean-webpack-plugin及glob插件并使用它们:
// webpack.prod.js
const ClearWebpackPlugin = require('clean-webpack-plugin') // 引入ClearWebpackPlugin插件
const merge = require('webpack-merge')
const common = require('./webpack.common')
const path = require('path')
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模块,用于扫描所有html文件中所引用的css
module.exports = merge(common, { // 将webpack.common.js合并到当前文件
devtool: 'source-map', // 会生成对于调试的完整的.map文件,但同时也会减慢打包速度
plugins: [
new ClearWebpackPlugin(['dist']), // 清理所要清理的文件夾名称
new PurifyCssWebpack({
paths: glob.sync(path.join(__dirname, 'src/*.html')) // 同步扫描全部html文件中所引用的css
})
]
})
复制代码
在index.css文件中增长一些多余的代码测试:
body {
background: gray;
}
#root div{
width: 200px;
margin-top: 50px;
transform: rotate(45deg); /* 这个属性会产生前缀 */
}
.a{ /* 冗余css */
color: black;
}
.b{ /* 冗余css */
width: 50px;
height: 50px;
background: yellow;
}
复制代码
而后咱们运行npm run build后发现打包后的index.css中是没有多余的.a和.b代码的:
body {
background: gray;
}
#root div {
width: 200px;
margin-top: 50px;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
/* 这个属性会产生前缀 */
}
/*# sourceMappingURL=index.css.map*/
复制代码
处理图片须要安装两个loader:
虽然咱们只需使用url-loader,但url-loader是依赖于file-loader的,因此也要安装
npm i url-loader file-loader -D
复制代码
而后在webpack.common.js中配置url-loader:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|svg|gif)$/, // 正则匹配图片格式
use: [
{
loader: 'url-loader' // 使用url-loader
}
]
}
]
},
...
}
复制代码
更新index.css, 背景改成背景
body {
background: gray;
background-image: url(../images/back.png) top right repeat-y;
}
...
复制代码
运行npm run dev后,背景图片变成了base64,由于webpack会自动优化图片,减小发送请求,可是若是我想把它变成路径的该怎么作? 能够把webpack.common.js的loader配置更改一下,增长options选项:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|svg|gif)$/, // 正则匹配图片格式
use: [
{
loader: 'url-loader', // 使用url-loader
options: {
limit: 1000 // 限制只有小于1kb的图片才转为base64,例子图片为384kb,因此不会被转化
}
}
]
}
]
},
...
}
复制代码
而后咱们运行npm run build后,再运行npm run dev,额,图片是没有转成base64了,可是图片怎么不显示了? 问题就出在路径上,咱们以前图片的路径是在../images文件夹下,可是打包出来后没有这个路径了,图片直接和文件同级了,因此咱们须要在webpack.common.js中给它设置一个文件夹:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.(png|jpg|svg|gif)$/, // 正则匹配图片格式
use: [
{
loader: 'url-loader', // 使用url-loader
options: {
limit: 1000, // 限制只有小于1kb的图片才转为base64,例子图片为384kb,因此不会被转化
outputPath: 'images' // 设置打包后图片存放的文件夹名称
}
}
]
}
]
},
...
}
复制代码
继续npm run build打包再npm run dev运行,个人天!图片仍是不显示! 调试工具上看图片路径有images文件夹了,可是个人../呢?
这涉及到配置路径的问题上了,咱们还须要在css-loader中给背景图片设置一个公共路径publicPath: '../',以下:
// webpack.common.js
...
module.exports = {
...
module: {
rules: [
...
{
test: /\.css$/, // 正则匹配以.css结尾的文件
use: ExtractTextPlugin.extract({ // 这里咱们须要调用分离插件内的extract方法
fallback: 'style-loader', // 至关于回滚,经postcss-loader和css-loader处理过的css最终再通过style-loader处理
use: [
{ loader: 'css-loader' },
{ loader: 'postcss-loader' }// 使用postcss-loader
], // 须要用的loader,必定是这个顺序,由于调用loader是从右往左编译的
publicPath: '../' // 给背景图片设置一个功能路径
})
},
{
test: /\.(png|jpg|svg|gif)$/, // 正则匹配图片格式
use: [
{
loader: 'url-loader', // 使用url-loader
options: {
limit: 1000, // 限制只有小于1kb的图片才转为base64,例子图片为384kb,因此不会被转化
outputPath: 'images' // 设置打包后图片存放的文件夹名称
}
}
]
}
]
},
...
}
复制代码
在webpack4.x版本中当你打包时会自动把js压缩了,并且npm run dev运行服务器时,当你修改代码时,热更新很慢,这是由于你修改后webpack又自动为你打包,这就致使了在开发环境中效率很慢,因此咱们须要把开发环境和生产环境区分开来,这时就体现出咱们代码分离的便捷性了,webpack.dev.js表明开发环境的配置,webpack.prod.js表明生产环境的配置,这时咱们只要在package.json文件中配置对应环境的命令便可:
{
...
"scripts": {
"build": "webpack --config webpack.prod.js --mode production",
"dev": "webpack-dev-server --open --config webpack.dev.js --mode development",
"test": "npm run test"
},
...
}
复制代码
--mode production表示打包时是生产环境,会本身将js进行压缩,而--mode development表示当前是开发环境,不须要进行压缩。这同时也解决了以前一直遗留的警告问题
项目背景:项目有三个分支、dev(开发分支)、uat(测试环境)、prod(上线环境) 如今须要:运行对应的命令npm run dev:dev、uat、prod以及npm run build:dev、uat、prod会调用对用的host
步骤以下
- 一、cross-env能跨平台地设置及使用环境变量,安装
npm i --save-dev cross-dev
- 二、config文件夹下新建dev.js(开发环境)、prod.js(生产环境)。配置文件以下
// dev.js
// 在任何文件里都能简单的用下面代码获取到配置
// const NODE_ENV = process.env.NODE_ENV
// const BRANCH = process.env.BRANCH
module.exports = {
NODE_ENV: "'development'", // 开发模式|生产模式
/*
* 一、process.env.BRANC 读取终端执行的npm命令
* 二、BRANCH: JSON.stringify(process.env.BRANCH) || 'dev':用于接受npm命令的修改
* 三、默认dev
*/
BRANCH: JSON.stringify(process.env.BRANCH) || "'dev'"
}
复制代码
// prod.js
// 在任何文件里都能简单的用下面代码获取到配置
// const NODE_ENV = process.env.NODE_ENV
// const BRANCH = process.env.BRANCH
module.exports = {
NODE_ENV: "'production'", // 开发模式|生产模式
/*
* 一、process.env.BRANC 读取终端执行的npm命令
* 二、BRANCH: JSON.stringify(process.env.BRANCH) || 'dev':用于接受npm命令的修改
* 三、默认dev
*/
BRANCH: JSON.stringify(process.env.BRANCH) || "'dev'"
}
复制代码
- 三、在package.json中配置npm 脚本以下:
{
...
"scripts": {
"dev": "webpack-dev-server --open --config webpack.dev.js --mode development",
"dev:dev": "cross-env BRANCH=dev webpack-dev-server --open --config webpack.dev.js --mode development"
...
},
...
}
复制代码
- 四、在webpack.dev.js中引入dev.js,webpack.prod.js引入prod.js 并将其设置为全局变量,具体以下
// webpack.dev.js
const dev = require('./config/dev')
...
module.exports = merge(common, {
...
plugins: [
new webpack.DefinePlugin({ // DefinePlugin能够在编译时期建立全局变量。
'process.env': dev
})
]
})
复制代码
// webpack.prod.js
...
const dev = require('./config/prod')
module.exports = merge(common, { // 将webpack.common.js合并到当前文件
plugins: [
...
new webpack.DefinePlugin({ // DefinePlugin能够在编译时期建立全局变量。
'process.env': dev
})
]
})
复制代码
- 五、 config文件下新建common.js,用于存放公共的方法,并配置
// common.js
module.exports = {
/**
* [getHost 根据执行脚本的具体命令,返回具体的请求IP]
* @return {[type]} [description]
*/
getHost () {
const BRANCH = `${process.env.BRANCH}`
let HOST = ''
switch (BRANCH) {
case 'dev' :
HOST = 'https://xxx.com'
break
default :
HOST = ''
}
return HOST
}
}
复制代码
- 六、 分别运行npm run build npm run dev使用. 就能够看到效果
// index.js
const { post } = require('./preset/request')
const promise = post({
url: '/xxx/xxx',
data: {
tenantCode: '88000531',
keyword: '',
page: {
size: 10,
page: 1
}
}
})
promise.then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})
复制代码
运行npm run build:dev,这样NODE_ENV便设置成功,无需担忧跨平台问题 在任何页面使用都能获取process.env.BRANCH
Axios具备如下特征:
- 从浏览器中建立 XMLHttpRequests
- 从 node.js 建立 http 请求
- 支持 Promise API 拦截请求和响应 转换请求数据和响应数据 取消请求 自动转换 JSON 数据 客户端支持防护 XSRF
安装命令:npm install axios
封裝请求的request.js
const HOST = require('../../config/common').getHost() // 获取命令后缀
const _axios = require('axios') // 使用axios
const axios = _axios.create({ // 建立实例
baseURL: HOST, // IP
timeout: 5000 // 请求超时时间
})
// 配置默认值
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
/**
* [description]
* @param {[type]} url [请求地址]
* @param {[type]} params [请求参数, 与url拼接的]
* @param {[type]} headers [请求头]
* @param {[type]} timeout [超时时间]
* @return {[type]} [返回promise]
*/
module.exports.get = function ({ url = '', params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.get(url, { params, timeout })
return promise
}
/**
* [POST请求]
* @param {[type]} url [请求地址]
* @param {[type]} data [请求参数]
* @param {[type]} params [地址拼接参数]
* @param {[type]} headers [请求头]
* @param {[type]} timeout [超时]
* @return {[type]} [返回promise]
*/
module.exports.post = function ({ url = '', data = {}, params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.post(url, { data, params, headers, timeout })
return promise
}
/**
* [PUT请求]
* @param {[type]} url [请求地址]
* @param {[type]} data [请求参数]
* @param {[type]} params [地址拼接参数]
* @param {[type]} headers [请求头]
* @param {[type]} timeout [超时]
* @return {[type]} [返回promise]
*/
module.exports.put = function ({ url = '', data = {}, params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.put(url, { data, params, headers, timeout })
return promise
}
/**
* [DELETE请求]
* @param {[type]} url [请求地址]
* @param {[type]} data [请求参数]
* @param {[type]} params [地址拼接参数]
* @param {[type]} headers [请求头]
* @param {[type]} timeout [超时]
* @return {[type]} [返回promise]
*/
module.exports._delete = function ({ url = '', data = {}, params = {}, headers = {}, timeout = 5000 }) {
const promise = axios.delete(url, { data, params, headers, timeout })
return promise
}
复制代码