demo15链接
首先新建一个文件夹:demo15,执行npm init -y初始化package.json,生成后的文件如下:
{"name": "demo15","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"}
我们先将无用的代码清除掉,只留下关键代码:
{"scripts": {}}
首先安装webpack所需依赖
npm i webpack webpack-cli webpack-dev-server —save-dev
安装babel7,因为目前主要使用ES6来编写代码,所以需要转译
npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime —save-dev
npm i @babel/polyfill @babel/runtime
现在package.json中的依赖为:
{"scripts": {},"license": "ISC","devDependencies": {"@babel/core": "^7.4.5","@babel/plugin-transform-runtime": "^7.4.4","@babel/preset-env": "^7.4.5","babel-loader": "^8.0.6","webpack": "^4.33.0","webpack-cli": "^3.3.4","webpack-dev-server": "^3.7.1"},"dependencies": {"@babel/polyfill": "^7.4.4","@babel/runtime": "^7.4.5"}}
新建.babelrc来配置babel插件,代码如下:
{"presets": ["@babel/preset-env"],"plugins": ["@babel/plugin-transform-runtime"]}
新建.browserslistrc文件配置该项目所支持的浏览器版本:
# 所支持的浏览器版本> 1% # 全球使用情况统计选择的浏览器版本last 2 version # 每个浏览器的最后两个版本not ie <= 8 # 排除小于 ie8 及以下的浏览器
在开始配置webpack.config.js文件之前,需要注意一下,因为我们现在有两种模式,production(生产)和development(开发)模式。
安装自动生成html依赖
npm i html-webpack-plugin html-loader clean-webpack-plugin —save-dev
安装css/字体图标处理依赖
npm i css-loader style-loader mini-css-extract-plugin optimize-css-assets-webpack-plugin —save-dev
安装scss处理依赖
npm i node-sass sass-loader —save-dev
为不同内核的浏览器加上CSS前缀
npm install postcss-loader autoprefixer —save-dev
图片及字体处理
npm i url-loader file-loader image-webpack-loader —save-dev
第三方js库
npm i jquery
安装了这些依赖后的package.json为:
{"scripts": {},"license": "ISC","devDependencies": {"@babel/core": "^7.4.5","@babel/plugin-transform-runtime": "^7.4.4","@babel/preset-env": "^7.4.5","autoprefixer": "^9.6.0","babel-loader": "^8.0.6","clean-webpack-plugin": "^3.0.0","css-loader": "^2.1.1","file-loader": "^4.0.0","html-loader": "^0.5.5","html-webpack-plugin": "^3.2.0","image-webpack-loader": "^5.0.0","mini-css-extract-plugin": "^0.7.0","node-sass": "^4.12.0","optimize-css-assets-webpack-plugin": "^5.0.1","postcss-loader": "^3.0.0","sass-loader": "^7.1.0","style-loader": "^0.23.1","url-loader": "^2.0.0","webpack": "^4.33.0","webpack-cli": "^3.3.4","webpack-dev-server": "^3.7.1"},"dependencies": {"@babel/polyfill": "^7.4.4","@babel/runtime": "^7.4.5","jquery": "^3.4.1"}}
之前我们大多都是写生产模式,也就是经常说的打包,但是我们日常开发项目,用的是开发模式。
只有在项目做完后,要部署到nginx上的时候才使用生产模式,将代码打包放到nginx中
之所以要分两种模式是因为,开发模式下,需要加快编译的速度,可以热更新以及设置跨域地址,开启源码调试(devtool:’source-map‘)
而生产模式下,则需要压缩js/css代码,拆分公用代码,拆分第三方的js库**等。
所以这里的配置我们分成三个文件夹来写,一个是生产配置,一个是开发配置,另外一个是基础配置。
即:webpack.base.conf.js(基础配置),webpack.dev.conf.js(开发配置),webpack.prod.conf.js(生产配置)
新建build文件夹,创建上述是哪个文件,项目结构为:
这里需要使用到一个插件,webpack-merge来合并配置,比如开发环境就合并开发环境+基础配置,生产就合并生产配置+基础配置
npm i webpack-werge —save-dev
首先简单写个webpack.base.conf.js的示例代码:
const merge = require('webpack-merge')const productionConfig = require('./webpack.prod.conf') // 引入生产环境配置文件const developmentConfig = require('./webpack.dev.conf') // 引入开发环境配置文件const baseConfig = {} // ... 省略module.exports = env => {let config = env === 'production' ? productionConfig : developmentConfigreturn merge(baseConfig, config) // 合并 公共配置 和 环境配置}
- 引入webpack-merge插件来合并配置
- 引入生产环境和开发环境
- 编写基础配置
- 导出合并后的配置文件
在代码中区分不同环境:
module.exports = env => {let config = env === 'production' ? productionConfig : developmentConfigreturn merge(baseConfig, config) // 合并 公共配置 和 环境配置}
这里的env在package.json中进行配置,修改script,添加’dev‘和’build‘命令
注意,这里有个—dev字段与 webpack.base.conf.js 中的 env 是联动的,告诉它当前是什么环境,然后合并成什么环境
{"scripts": {"dev": "webpack-dev-server --env development --open --config build/webpack.base.conf.js","build": "webpack --env production --config build/webpack.base.conf.js"}}
(一)编写基础配置
const webpack = require('webpack')const merge = require('webpack-merge')const HtmlWebpackPlugin = require('html-webpack-plugin')const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件const CleanWebpackPlugin = require('clean-webpack-plugin')const path = require('path')const productionConfig = require('./webpack.prod.conf.js') // 引入生产环境配置文件const developmentConfig = require('./webpack.dev.conf.js') // 引入开发环境配置文件/*** 根据不同的环境,生成不同的配置* @param {String} env "development" or "production"*/const generateConfig = env => {// 将需要的 Loader 和 Plugin 单独声明let scriptLoader = [{loader: 'babel-loader'}]let cssLoader = ['style-loader','css-loader','postcss-loader', // 使用 postcss 为 css 加上浏览器前缀'sass-loader' // 使用 sass-loader 将 scss 转为 css]let cssExtractLoader = [{loader: MiniCssExtractPlugin.loader},'css-loader','postcss-loader', // 使用 postcss 为 css 加上浏览器前缀'sass-loader', // 使用 sass-loader 将 scss 转为 css]let fontLoader = [{loader: 'url-loader',options: {name: '[name]-[hash:5].min.[ext]',limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg filepublicPath: 'fonts/',outputPath: 'fonts/'}}]let imageLoader = [{loader: 'url-loader',options: {name: '[name]-[hash:5].min.[ext]',limit: 10000, // size <= 10KBoutputPath: 'images/'}},// 图片压缩{loader: 'image-webpack-loader',options: {// 压缩 jpg/jpeg 图片mozjpeg: {progressive: true,quality: 50 // 压缩率},// 压缩 png 图片pngquant: {quality: '65-90',speed: 4}}}]let styleLoader =env === 'production'? cssExtractLoader // 生产环境下压缩 css 代码: cssLoader // 开发环境:页内样式嵌入return {entry: { app: './src/app.js' },output: {publicPath: env === 'development' ? '/' : './',path: path.resolve(__dirname, '..', 'dist'),filename: '[name]-[hash:5].bundle.js',chunkFilename: '[name]-[hash:5].chunk.js'},module: {rules: [{ test: /\.js$/, exclude: /(node_modules)/, use: scriptLoader },{ test: /\.(sa|sc|c)ss$/, use: styleLoader },{ test: /\.(eot|woff2?|ttf|svg)$/, use: fontLoader },{ test: /\.(png|jpg|jpeg|gif)$/, use: imageLoader }]},plugins: [// 开发环境和生产环境二者均需要的插件new HtmlWebpackPlugin({title: 'webpack4 实战',filename: 'index.html',template: path.resolve(__dirname, '..', 'index.html'),// chunks: ['app'],minify: {collapseWhitespace: true}}),new webpack.ProvidePlugin({ $: 'jquery' }),new CleanWebpackPlugin()]}}module.exports = env => {let config = env === 'production' ? productionConfig : developmentConfigreturn merge(generateConfig(env), config) // 合并 公共配置 和 环境配置}
(二)编写开发环境配置
const webpack = require("webpack");const path = require("path");module.exports = {mode: "development",devtool: "source-map", // 调试源码devServer: {contentBase: path.join(__dirname, "../dist/"),port: 8000,hot: true,overlay: true,proxy: {"/comments": {target: "https://m.weibo.cn",changeOrigin: true,logLevel: "debug",headers: {Cookie: ""}}},historyApiFallback: true},plugins: {new webpack.HotModuleReplacementPlugin(),new webpack.NamedChunksPlugin()}};
(三)编写生产环境配置
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 将 css 单独打包成文件const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); // 压缩cssmodule.exports = {mode: "production",optimization: {splitChunks: {chunks: "all",cacheGroups: {jquery: {name: "chunk-jquery", // 单独将 jquery 拆包priority: 15,test: /[\\/]node_modules[\\/]jquery[\\/]/}}}},plugins: [new MiniCssExtractPlugin({filename: "[name].css",chunkFilename: "[id].css"}),// 压缩cssnew OptimizeCssAssetsPlugin({assetNameRegExp: /\.css$/g, //一个正则表达式,指示应优化/最小化的资产的名称。提供的正则表达式针对配置中ExtractTextPlugin实例导出的文件的文件名运行,而不是源CSS文件的文件名。默认为/\.css$/gcssProcessor: require("cssnano"), //用于优化\最小化 CSS 的 CSS处理器,默认为 cssnanocssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默认为{}canPrint: true //一个布尔值,指示插件是否可以将消息打印到控制台,默认为 true})]};
(四)测试开发模式
运行 npm run dev
并且自动打开浏览器,图文和文字都出来了,打开控制台也能看到跨域成功、源码定位,因为将 devtool 设置为 ‘source-map’,所以就会生成 map 文件,体积较大
**
(五)测试生产模式
运行npm run build
打开 dist/index.html 文件
生产模式下跨域失败是很正常的,而且如果是 vue 项目打包完之后是无法直接打开 index.html 文件查看效果的,必须要放在服务器上,一般都是将打包后的文件放入 nginx 中,在 nginx 中配置跨域地址
还有一种配置 webpack 开发和生产环境的方式,会比较常用:
修改 webpack.base.conf.js
const path = require('path')const webpack = require('webpack')const HtmlWebpackPlugin = require('html-webpack-plugin')const CleanWebpackPlugin = require('clean-webpack-plugin')module.exports = {entry: {app: './src/app.js'},output: {path: path.resolve(__dirname, '..', 'dist')},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: [{loader: 'babel-loader'}]},{test: /\.(png|jpg|jpeg|gif)$/,use: [{loader: 'url-loader',options: {name: '[name]-[hash:5].min.[ext]',limit: 1000, // size <= 1KBoutputPath: 'images/'}},// img-loader for zip img{loader: 'image-webpack-loader',options: {// 压缩 jpg/jpeg 图片mozjpeg: {progressive: true,quality: 65 // 压缩率},// 压缩 png 图片pngquant: {quality: '65-90',speed: 4}}}]},{test: /\.(eot|ttf|svg)$/,use: {loader: 'url-loader',options: {name: '[name]-[hash:5].min.[ext]',limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg filepublicPath: 'fonts/',outputPath: 'fonts/'}}}]},plugins: [// 开发环境和生产环境二者均需要的插件new HtmlWebpackPlugin({title: 'webpack4 实战',filename: 'index.html',template: path.resolve(__dirname, '..', 'index.html'),minify: {collapseWhitespace: true}}),new webpack.ProvidePlugin({ $: 'jquery' }),new CleanWebpackPlugin()],performance: false}
修改 webpack.dev.conf.js
const webpack = require('webpack')
const merge = require('webpack-merge')
const commonConfig = require('./webpack.base.conf.js')
const path = require('path')
const devConfig = {
mode: 'development',
output: {
filename: '[name].js',
chunkFilename: '[name].js'
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在一个 css 中引入了另一个 css,也会执行之前两个 loader,即 postcss-loader 和 sass-loader
}
},
'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
'sass-loader' // 使用 sass-loader 将 scss 转为 css
]
}
]
},
devtool: 'cheap-module-eval-soure-map',
devServer: {
contentBase: path.join(__dirname, '../dist/'),
port: 8000,
hot: true,
overlay: true,
proxy: {
'/comments': {
target: 'https://m.weibo.cn',
changeOrigin: true,
logLevel: 'debug',
headers: {
Cookie: ''
}
}
},
historyApiFallback: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
]
}
module.exports = merge(commonConfig, devConfig)
修改 webpack.prod.conf.js
const merge = require('webpack-merge')
const commonConfig = require('./webpack.base.conf.js')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 单独打包成文件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 压缩 css
const prodConfig = {
mode: 'production',
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
},
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
importLoaders: 2 // 在一个 css 中引入了另一个 css,也会执行之前两个 loader,即 postcss-loader 和 sass-loader
}
},
'postcss-loader', // 使用 postcss 为 css 加上浏览器前缀
'sass-loader' // 使用 sass-loader 将 scss 转为 css
]
}
]
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
jquery: {
name: 'jquery', // 单独将 jquery 拆包
priority: 15,
test: /[\\/]node_modules[\\/]jquery[\\/]/
},
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors'
}
}
}
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]-[contenthash].css',
chunkFilename: '[id]-[contenthash].css'
}),
// 压缩 css
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g, //一个正则表达式,指示应优化/最小化的资产的名称。提供的正则表达式针对配置中ExtractTextPlugin实例导出的文件的文件名运行,而不是源CSS文件的文件名。默认为/\.css$/g
cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处理器,默认为 cssnano
cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默认为{}
canPrint: true //一个布尔值,指示插件是否可以将消息打印到控制台,默认为 true
})
]
}
module.exports = merge(commonConfig, prodConfig)
修改package.json的script配置命令
{
"scripts": {
"dev": "webpack-dev-server --open --config ./build/webpack.dev.conf.js",
"build": "webpack --config ./build/webpack.prod.conf.js"
}
}
在之前的基础上重新更改了配置,可以打包在看下
