1.新建项目webpack-democss
2.安装webpackhtml
npm install webpack webpack-cli -gvue
3.项目初始化node
npm init -y //-y默认全部的配置webpack
安装依赖环境es6
npm i webpack webpack-cli -Dweb
//-D webpack安装在devDependencies环境中正则表达式
1.package.json里配置咱们的scriptsvuex
{
"name": "webpack_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production"
//咱们在这里配置,就可使用npm run build 打包咱们的项目 像使用vue-cli脚手架那样
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.39.3",
"webpack-cli": "^3.3.8"
}
}
复制代码
新建webpack.config.js文件 新建index.html文件vue-cli
必须都在根目录下面 webpack默认找根目录下的配置
配置咱们的入口entry,在vue-cli里至关于跟目录下的main.js,咱们的出口output。咱们能够把webpack理解为一个工厂,进入至关于把各类各样的原料放进咱们的工厂了,而后工厂进行一系列的打包操做把打包好的东西,向外输出,而后就能够去出售了(上线)。
插件来将 HTML 引用路径和咱们的构建结果关联起来。 npm run buid 以后 dist 目录就会多个 index.html 并引入了 main.js.
new HtmlWebpackPlugin({
title: 'webpack-demo',//标题
filename: 'index.html', // 配置输出文件名和路径
template: './index.html', // 配置要被编译的html文件
inject: true,//script标签位于html文件的body底部 true/body/head/false 默认true
favicon: './src/assets/img/logo.png',//指定页面图标 而后在生成的html中就有一个link标签:<link rel='shortcut icon' href='example.ico'>
// 压缩 => production 模式使用
//生产为true 其余的时候为false
minify: {
caseSensitive:false,//是否大小写敏感 默认flase
removeAttributeQuotes: true, //去掉属性引用 删除双引号 默认false
collapseWhitespace: true, //是否去除空格 折叠 html 为一行 默认false
removeComments:true//去注释 默认false
},
hash: true,//是否生成hash添加在引入文件地址的末尾,这个能够避免缓存带来的麻烦。默认为false。
cache: true,//默认是true的,表示内容变化的时候生成一个新的文件。
showErrors: true,//是否将错误信息写在页面里,默认true,出现错误信息则会包裹在一个pre标签内添加到页面上。
chunks:'' //引入的模块,这里指定的是entry中设置多个js时,在这里指定引入的js,若是不设置则默认所有引入。
chunksSortMode: '' //这个选项决定了 script 标签的引用顺序。默认有四个选项,'none' | 'auto' | 'dependency' | 'manual' | {Function}
- none: 无序
- auto: 默认值, 按插件内置的排序方式
- dependency: 根据不一样文件的依赖关系排序(通常用于生产)
- manual: chunks按引入的顺序排序, 即属性chunks的顺序
- {Function}: 指定具体的排序规则
})
复制代码
咱们但愿使用 webpack 来进行构建 css 文件,为此,须要在配置中引入 loader 来解析和处理 CSS 文件:
npm install style-loader css-loader -D
在src的assets里面的css文件中新增color.css添加样式,在index.js中引入这个css import './assets/css/color.css'
在webpack.config.js中配置loader
module: {
/**
* test: 匹配特定条件。通常是提供一个正则表达式或正则表达式的数组
* include: 匹配特定条件。通常是提供一个字符串或者字符串数组
* exclude: 排除特定条件
* and: 必须匹配数组中的全部条件
* or: 匹配数组中任何一个条件,
* nor: 必须排除这个条件
*/
rules: [
{
test: /\.css$/,
include: [path.resolve(__dirname, 'src')],
use: ['style-loader', 'css-loader']
}
]
}
复制代码
经由上述两个 loader 的处理后,CSS 代码会转变为 JS, 若是须要单独把 CSS 文件分离出来,咱们须要使用 mini-css-extract-plugin 插件
抽取 css 到独立文件, 自动添加前缀
npm i mini-css-extract-plugin postcss-loader autoprefixer -D
咱们在写 css 时难免要考虑到浏览器兼容问题,如 transform 属性,须要添加浏览器前缀以适配其余浏览器。故使用到 postcss-loader 这个 loader, 下面则是相关的配置
注意: 若是浏览器前缀添加不成功,记得要在autoprefixer后面加("last 100 versions")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/,
include: [path.resolve(__dirname, 'src')],
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',//为了防止css里面有引用背景图片 图片打包以后在dist/images路径错误问题
hmr: devMode, // 仅dev环境启用HMR功能
}
},
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')("last 100 versions")]
}
}
]
}
]
},
plugins: [
//...
new MiniCssExtractPlugin({
// 这里的配置和webpackOptions.output中的配置类似
// 便可以经过在名字前加路径,来决定打包后的文件存在的路径
filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
})
]
}
复制代码
npm install file-loader url-loader -D
file-loader: 能够用于处理不少类型的文件,它的主要做用是直接输出文件,把构建后的文件路径返回。
url-loader: 若是图片较多,会发不少 http 请求,会下降页面性能。url-loader 会将引入的图片编码,生成 dataURl。至关于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只须要引入这个文件就能访问图片了。固然,若是图片较大,编码会消耗性能。所以 url-loader 提供了一个 limit 参数,小于 limit 字节的文件会被转为 DataURl,大于 limit 的还会使用 file-loader 进行 copy。
配置以下:
module.exports = {
module: {
rules: [
// ...
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
outputPath: 'images/', //输出到images文件夹
limit: 10000, //是把小于6000B的文件打成Base64的格式,写入JS
name: "[name]-[hash:5].min.[ext]",
}
}
]
}
]
}
//...
}
复制代码
如今随着es6的普及,愈来愈多的代码使用es6了,可是不少浏览器并不支持es6,好比async/awiat,const。所以须要咱们引用babe来把咱们es6的代码编译为es5。在跟目录下新建.babelrc,简单配置下
{"presets": ["env"]}
安装所需依赖:npm i babel-loader babel-core babel-preset-env -D
{
test: /\.js$/, //es6 => es5
exclude: /node_modules/,
use: 'babel-loader'
}
复制代码
报错:Error: Cannot find module '@babel/core' babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7' 由于babel-loader的版本问题
先卸载 npm uninstall babel-loader 重装一个@7的版本 npm i babel-loader@7 -D
npm install clean-webpack-plugin -D
配置以下:
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
plugins: [
new CleanWebpackPlugin(['dist'])
]
}
复制代码
报错:TypeError: CleanWebpackPlugin is not a constructor 修改引用方式:const {CleanWebpackPlugin} = require('clean-webpack-plugin');
又报错:Error: clean-webpack-plugin only accepts an options object 修改调用方式,不传入目录:new CleanWebpackPlugin()
假如你 a.js 和 b.js 都 import 了 c.js 文件,这段代码就冗杂了。为何要提取公共代码,简单来讲,就是减小代码冗余,提升加载速度。
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
// 抽离本身写的公共代码
chunks: 'initial',
name: 'common', // 打包后的文件名,任意命名
minChunks: 2, //最小引用2次
minSize: 0 // 只要超出0字节就生成一个新包
},
styles: {
name: 'styles', // 抽离公用样式
test: /\.css$/,
chunks: 'all',
minChunks: 2,
enforce: true
},
vendor: {
// 抽离第三方插件
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'vendor', // 打包后的文件名,任意命名
// 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
priority: 10
}
}
}
}
}
复制代码
hash 是干吗用的? 咱们每次打包出来的结果可能都是同一个文件,那我上线的时候是否是要替换掉上线的 js,那我怎么知道哪是最新的呢,咱们通常会清一下缓存。而 hash 就是为了解决这个问题而存在的
module.exports = {
//...
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js'
},
//...
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
})
]
}
复制代码
若是咱们能够精简 resolve 配置,让 webpack 在查询模块路径时尽量快速地定位到须要的模块,不作额外的查询工做,那么 webpack 的构建速度也会快一些
module.exports = {
resolve: {
/**
* alias: 别名的配置
*
* extensions: 自动解析肯定的扩展,
* 好比 import 'xxx/theme.css' 能够在extensions 中添加 '.css', 引入方式则为 import 'xxx/theme'
* @default ['.wasm', '.mjs', '.js', '.json']
*
* modules 告诉 webpack 解析模块时应该搜索的目录
* 若是你想要添加一个目录到模块搜索目录,此目录优先于 node_modules/ 搜索
* 这样配置在某种程度上能够简化模块的查找,提高构建速度 @default node_modules 优先
*/
extensions: ['.vue', '.js', '.json','.css'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@':
path.resolve(__dirname, 'src'),
'@components':
path.resolve(__dirname, 'src/components/'),
'@assets':
path.resolve(__dirname, 'src/assets'),
},
modules: [path.resolve(__dirname, 'src'), 'node_modules']
}
}
复制代码
安装:npm install webpack-dev-server -D package.json 中 scripts 中添加:"dev": "webpack-dev-server --mode development"
devServer: {
host: '0.0.0.0',//主机名
port: 8080,//端口
open: true,//自动打开浏览器
compress: true,//服务器压缩
hot:true,//热更新
inline:true,//页面自动刷新
//跨域问题
proxy:{
'/api': {
target: 'https://testbi.promni.cn/v2/api',
secure: false,
changeOrigin: true,
pathRewrite: {'^/api' : ''}
}
},
},
复制代码
模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程当中替换、添加或删除模块,而无需从新加载整个页面。主要是经过如下几种方式,来显著加快开发速度:
保留在彻底从新加载页面时丢失的应用程序状态。 只更新变动内容,以节省宝贵的开发时间。 调整样式更加快速 - 几乎至关于在浏览器调试器中更改样式。
上面咱们 npm start 后修改一次文件,页面就会刷新一次。这样就存在很大问题了,好比咱们使用 redux, vuex 等插件,页面一刷新那么存放在 redux, vuex 中的东西就会丢失,很是不利于咱们的开发。
import webpack from 'webpack';
plugins: [
new webpack.HotModuleReplacementPlugin()
//...
]
配置后还不行,由于 webpack 还不知道你要更新哪里, 修改 src/index.js 文件, 添加
if (module.hot) {
module.hot.accept()
}
复制代码
可是可是有个问题是,你修改 css/less 等样式文件并未发生改变, what ? HMR 修改样式表 须要借助于 style-loader, 而咱们以前用的是 MiniCssExtractPlugin.loader, 这也好办,修改其中一个 rules 就能够了,咱们能够试试改
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [
// MiniCssExtractPlugin.loader,
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')] // 添加css中的浏览器前缀
}
},
'less-loader'
]
}
]
}
}
复制代码
咱们能够发现,dev 下配置的 loader 为 style-loader , 而生产环境下则是须要 MiniCssExtractPlugin.loader 这就涉及到了不一样环境之间的配置。能够经过 process.env.NODE_ENV 获取当前是开发环境或者是生产环境,而后配置不一样的 loader,这里就不作展开了
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
//打包入口
entry: {
main: './src/index.js',
page1: "./src/assets/js/page1.js",//测试提取公用代码
page2: "./src/assets/js/page2.js",//测试提取公用代码
},
//打包出口
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js'
},
module: {
/**
* test: 匹配特定条件。通常是提供一个正则表达式或正则表达式的数组
* include: 匹配特定条件。通常是提供一个字符串或者字符串数组
* exclude: 排除特定条件
* and: 必须匹配数组中的全部条件
* or: 匹配数组中任何一个条件,
* nor: 必须排除这个条件
*/
rules: [
{
test: /\.css$/,
include: [path.resolve(__dirname, 'src')],
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',//为了防止css里面有引用背景图片 图片打包以后在dist/images路径错误问题
hmr: devMode, // 仅dev环境启用HMR功能
}
},
// 'style-loader', 模块热替换时候用的
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')("last 100 versions")]//添加浏览器前缀
}
}
]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
outputPath: 'images/', //输出到images文件夹
limit: 6000, //是把小于6000B的文件打成Base64的格式,写入JS
name: "[name]-[hash:5].min.[ext]",
}
}
]
},
{
test: /\.js$/, //es6 => es5
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack-demo',//标题
filename: 'index.html', // 配置输出文件名和路径
template: './index.html', // 配置要被编译的html文件
favicon: './src/assets/img/logo.png',//指定页面图标 而后在生成的html中就有一个link标签:<link rel='shortcut icon' href='example.ico'>
// 压缩 => production 模式使用
minify: {
removeAttributeQuotes: true, //去掉属性引用 删除双引号
collapseWhitespace: true, //是否去除空格 折叠 html 为一行
removeComments: true//去注释
},
hash: true,//是否生成hash添加在引入文件地址的末尾,这个能够避免缓存带来的麻烦。默认为true。
}),
new MiniCssExtractPlugin({
// 这里的配置和webpackOptions.output中的配置类似
// 便可以经过在名字前加路径,来决定打包后的文件存在的路径
filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
}),
//清理源目录文件
new CleanWebpackPlugin(),
//模块热替换
new webpack.HotModuleReplacementPlugin()
],
optimization: {
//压缩文件 mode:production 生产环境配置
minimizer: [
new OptimizeCssAssetsWebpackPlugin(),// 压缩css
new UglifyJsPlugin()//压缩js
],
//提取公用代码
splitChunks: {
cacheGroups: {
commons: {
// 抽离本身写的公共代码
chunks: 'initial',
name: 'common', // 打包后的文件名,任意命名
minChunks: 2, //最小引用2次
minSize: 0 // 只要超出0字节就生成一个新包
},
styles: {
name: 'styles', // 抽离公用样式
test: /\.css$/,
chunks: 'all',
minChunks: 2,
enforce: true
},
vendor: {
// 抽离第三方插件
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'vendor', // 打包后的文件名,任意命名
// 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
priority: 10
}
}
}
},
// 减小 resolve 的解析,配置别名
resolve: {
extensions: ['.vue', '.js', '.json', '.css'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@':
path.resolve(__dirname, 'src'),
'@components':
path.resolve(__dirname, 'src/components/'),
'@assets':
path.resolve(__dirname, 'src/assets'),
},
},
//webpack-dev-server mode:development 开发环境配置
devServer: {
host: '0.0.0.0',//主机名
port: 8080,//端口
open: true,//自动打开浏览器
compress: true,//服务器压缩
hot: true,//热更新
inline: true,//页面自动刷新
//跨域问题
proxy: {
'/api': {
target: 'https://testbi.promni.cn/v2/api',
secure: false,
changeOrigin: true,
pathRewrite: {'^/api': ''}
}
},
},
};
复制代码