webpack.config.js
// webpack loader列表
// https://doc.webpack-china.org/loaders/less-loader
// webpack plugin列表
// https://github.com/webpack-contrib/awesome-webpack#webpack-plugins
const path = require('path')
const webpack = require('webpack')
const UglifyPlugin = require('uglifyjs-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
// webpack 3.0 在script中配置
console.log('ENV =====>', process.env.NODE_ENV)
/*
webpack 4.0 暴露一个函数,可以获取到mode的环境变量
module.exports = (env, argv) => {
console.log(env, argv.mode)
return { ... }
} */
module.exports = {
entry: {
// 入口
vendor: ["vue"],
index: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
// filename: 'bundle.js'
// name 是根据entry中的[index]名字
// filename: '[name]_[hash].js'
// ?rd=[hash] 配合HtmlWebpackPlugin,可以将js插入html中加上随机数
// 使用chunkhash,最大程度实现缓存
// 热更新(HMR)不能和[chunkhash]同时使用。 解决:如果是开发环境,将配置文件中的chunkhash 替换为hash
filename: '[name].js?rd=[hash:8]',
// chunk的文件名可以单独指定,懒加载可看index.js中
chunkFilename: '[name].js?rd=[hash:5]',
},
// webpack 中有一个很关键的模块 enhanced-resolve 就是处理依赖模块路径的解析的
resolve: {
modules: [
// 使用绝对路径指定项目 node_modules,不做过多(一层层)查询
path.resolve(__dirname, 'node_modules'),
],
extensions: ['.vue', '.js', '.json', '.jsx', '.css'],
alias: {
'css': path.resolve(__dirname, 'src/assets/css')
}
},
// webpack 中提供一种处理多种文件格式的机制,便是使用 loader。我们可以把 loader 理解为是一个转换器,负责把某种文件格式的内容转换成 webpack 可以支持打包的模块。
module: {
rules: [{
// 匹配文件路径的正则表达式,通常我们都是匹配文件类型后缀
test: /\.(less|css)$/,
include: [
// 指定哪些路径下的文件需要经过 loader 处理,node_module不需要处理,性能问题
// 方法会把一个路径或路径片段的序列解析为一个绝对路径。
// http://nodejs.cn/api/path.html#path_path_resolve_paths
path.resolve(__dirname, 'src')
],
// 指定使用的loader
// 如果需要单独把 CSS 文件分离出来,我们需要使用 extract-text-webpack-plugin 插件。 并且在plugin中new一个配置实例
use: ExtractTextPlugin.extract({
use: [{
// 必须排在less-loader前面 !!
loader: 'css-loader',
options: {
minimize: true, // 使用 css 的压缩功能
},
},
// 1. loader: 'postcss-loader'
// 2. postcss-loader、autoprefixer
// 3. .postcssrc.js
/*
module.exports = {
"plugins": {
// 4. to edit target browsers: use "browserlist" field in package.json
"autoprefixer": {}
}
}
*/
/*
"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
] */
{ loader: 'postcss-loader'},
{ loader: 'less-loader' }
],
fallback: 'style-loader'
}),
/* use: [
// 负责解析 CSS 代码,主要是为了处理 CSS 中的依赖,例如 @import 和 url() 等引用外部文件的声明
// 'css-loader',
// 会将 css-loader 解析的结果转变成 JS 代码,运行时【动态】插入 style 标签来让 CSS 代码生效
// 'style-loader',
]*/
},
{
test: /\.(png|jpg|gif)$/,
include: [
path.resolve(__dirname, 'src')
],
use: [{
// url-loader 和 file-loader 的功能类似,但前者可以转成base64
// 单位是 Byte,当文件小于 8KB 时作为 DataURL 处理
// 顺序需要放在image-webpack-loader压缩上面 !!
loader: 'url-loader',
options: {
limit: 8192,
},
},{
// image-webpack-loader 的压缩是使用 imagemin 提供的一系列图片压缩类库来处理的
loader: 'image-webpack-loader',
options: {
mozjpeg: { // 压缩 jpeg 的配置
progressive: true,
quality: 65
},
optipng: { // 使用 imagemin-optipng 压缩 png,enable: false 为关闭
enabled: false,
},
pngquant: { // 使用 imagemin-pngquant 压缩 png
quality: '65-90',
speed: 4
},
gifsicle: { // 压缩 gif 的配置
interlaced: false,
},
webp: { // 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式
quality: 75
}
}
}]
},
{
test: /\.jsx?/, // 支持 js 和 jsx;x可有可无
include: [
// src 目录下的才需要经过 babel-loader 处理
path.resolve(__dirname, 'src'),
],
loader: 'babel-loader',
}
]
},
// 模块代码转换的工作由 loader 来处理,除此之外的其他任何工作都可以交由 plugin 来完成。
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
}),
// 直接将static文件复制到dist中
new CopyWebpackPlugin([
{ from: 'static/*.*', to: '', }
]),
// webpack 4.x 版本运行时,mode 为 production 即会启动压缩 JS 代码的插件,屏蔽此插件,3.x可以用这个插件
new UglifyPlugin(),
// 如果我们的文件名或者路径会变化,例如使用 [hash] 来进行命名,那么最好是将 HTML 引用路径和我们的构建结果关联起来,这个时候我们可以使用 html-webpack-plugin。
// 如果需要添加多个页面关联,那么实例化多个 html-webpack-plugin, 并将它们都放到 plugins 字段数组中就可以了。
new HtmlWebpackPlugin({
filename: 'index.html', // 配置输出文件名和路径
template: './index.html', // 配置html文件模板,将js和这个关联起来
minify: { // 压缩 HTML 的配置
minifyCSS: true, // 压缩 HTML 中出现的 CSS 代码
minifyJS: true, // 压缩 HTML 中出现的 JS 代码
removeComments: true, // 注释
collapseWhitespace: true, // 空格
removeAttributeQuotes: true // 属性引号
}
}),
// 使用方式特别,除了在plugins字段添加插件实例之外,还需要调整 loader 对应的配置。
// 配置输出的文件名,这里同样可以使用 [hash],多个文件会加载在一起
// name 是根据entry中的[index]名字
new ExtractTextPlugin({
filename: 'index.css?rd=[hash:8]'
}),
// 用于启动 HMR 时可以显示模块的相对路径
// 在 HMR 更新的浏览器控制台中打印更易读的模块名称
new webpack.NamedModulesPlugin(),
// Hot Module Replacement 的插件
//【在这个概念出来之前,我们使用过 Hot Reloading,当代码变更时通知浏览器刷新页面】
//【HMR 可以理解为增强版的 Hot Reloading,不用整个页面刷新,而局部替换掉模块】
new webpack.HotModuleReplacementPlugin(),
// webpack3.* 代码chunks分离
/* new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', // 使用 vendor 入口作为公共部分
filename: "vendor.js",
// minChunks: 3, // 公共的部分必须被 3 个 chunk 共享
minChunks: Infinity, // 这个配置会让webpack不再自动抽离公共模块,不管超过多少都不抽离,只抽离指定的vendor
}) */
],
// 在 webpack 的配置中,可以通过 devServer 字段来配置 webpack-dev-server,如端口设置、启动 gzip 压缩等,这里简单讲解几个常用的配置。
devServer: {
// public: 'http://localhost:8080/', // public 字段用于指定静态服务的域名
// publicPath: 'static/', // 字段用于指定构建好的静态文件在浏览器中用什么路径去访问
port: '1234',
hot: true, // 模块热替换
before(app) {
// 当访问 /some/path 路径时,返回自定义的 json 数据
// 可以用于拦截部分请求返回特定内容,或者实现简单的数据 mock。
app.get('/api/test.json', function (req, res) {
res.json({ code: 200, message: 'hello world' })
})
},
/* proxy: {
'/login': {
target: 'http://127.0.0.1:8090',
changeOrigin: true,
pathRewrite: {
'^/login': '/login'
}
},
} */
},
optimization: {
// webpack4.* chunks分离
splitChunks: {
// chunks: "all", // 所有的 chunks 代码公共的部分分离出来成为一个单独的文件
cacheGroups: {
vendor: {
chunks: "initial",
test: "vendor",
name: "vendor", // 使用 vendor 入口作为公共部分
enforce: true,
},
}
}
},
}
/* env相关总结(dev和build一样):
webpack 3:
package.json中 "start_": "NODE_ENV=development webpack-dev-server"
1.在webpack.config.js中可以获取 process.env.NODE_ENV
2.在runtime项目代码中【不能】获取到 process.env.NODE_ENV,默认为production。要想在项目中获取,需要webpack.DefinePlugin这个plugin设置
webpack 4:
package.json中 "start": "webpack-dev-server --mode development"
1. 在webpack.config.js中【不能】获取process.env.NODE_ENV,需要把配置作为函数返回值暴露 module.exports = (env, argv) => {},其中arv.mode可以获取
2. 在runtime项目代码中可以获取到 process.env.NODE_ENV。(注意不要设置webpack.DefinePlugin)
3. 更加快速的增量编译构建。(hot reload比 webpack 3比较快)
*/
/*
webpack 4.x 需要指定 mode 为 production,而 webpack 3.x 的话需要配置 UglifyJsPlugin。启动了之后,构建出来的结果就会移除【无用的代码】的那一部分代码了。
如果你在项目中使用了 Babel 的话,要把 Babel 解析模块语法的功能关掉,在 .babelrc 配置中增加 "modules": false 这个配置
*/
.babelrc
{
"presets": [["env", { "modules": false }]],
"plugins": [
"syntax-dynamic-import"
]
}
.postcssrc.js
module.exports = {
"plugins": {
// to edit target browsers: use "browserlist" field in package.json
"autoprefixer": {}
}
}
package.json
{
"name": "webpack_",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production",
"build_": "NODE_ENV=production webpack",
"start": "webpack-dev-server --mode development",
"start_": "NODE_ENV=development webpack-dev-server --mode development"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^8.4.1",
"babel-loader": "^7.1.4",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-preset-env": "^1.6.1",
"chalk": "^2.4.1",
"copy-webpack-plugin": "^4.5.1",
"css-loader": "^0.28.11",
"express": "^4.16.3",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^4.2.0",
"less": "^3.0.2",
"less-loader": "^4.1.0",
"opn": "^5.3.0",
"ora": "^2.1.0",
"postcss-loader": "^2.1.5",
"style-loader": "^0.21.0",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-loader": "^1.0.1",
"webpack": "^4.6.0",
"webpack-cli": "^2.1.2",
"webpack-dev-middleware": "^3.1.3",
"webpack-dev-server": "^3.1.4"
},
"dependencies": {
"vue": "^2.5.16"
},
"browserslist": [
"defaults",
"not ie < 8",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
]
}
dev.js
const webpack = require('webpack')
const chalk = require('chalk')
const opn = require('opn')
const ora = require('ora')
// 就是在 Express 中提供 webpack-dev-server 静态服务能力的一个中间件 【dev】
const midddleware = require('webpack-dev-middleware')
const webpackOptions = require('./webpack.config.js')
const spinner = ora({
text: chalk.magenta('> 加载中...'),
spinner: 'bouncingBar'
}).start()
const port = 3000
// 本地的开发环境默认就是使用development mode
webpackOptions.mode = 'development'
const compiler = webpack(webpackOptions)
const express = require('express')
const app = express()
let hotMidddleware = midddleware(compiler, {
// webpack-dev-middleware 的配置选项
})
app.use(hotMidddleware)
hotMidddleware.waitUntilValid(() => {
spinner.stop()
console.log(chalk.magenta('> 编译完成...'))
console.log(chalk.magenta(`> 监听:http://localhost:${port}\n`))
opn(`http://localhost:${port}`)
})
app.listen(port, () => {
console.log(chalk.magenta('> 项目运行...'))
})
前端架构师大佬qq群:634196762