导语:
我们在使用webpack的过程中,总是会看到项目里很多文件,但是对于新手来说,可能不知道它们对应的作用,秉持着能用就行,不需要看懂,够用就行。这种相信是大部分人都是这种想法,包括以前的我,这种想法是错的。
想要进阶,就必须会修改webpack的配置,要想会修改,就必须懂这些文件,代码的作用。
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
// 返回资源文件存放的路径
exports.assetsPath = function (_path) {
//判断当前是开发模式还是生产模式
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
//生成cssLoaders,用于加载.vue文件中的样式。
exports.cssLoaders = function (options) {
options = options || {
}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// 生成要与提取文本插件一起使用的加载程序字符串
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({
}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', {
indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// 生成styleloaders用于加载不在.vue文件中的css样式
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
/**
* 结束添加
* @returns {Function}
*/
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
/**
* 获取绝对路径
* @param dir
* @returns {*|string}
*/
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
//eslint的配置
const createLintingRule = () => ({
//对.js和.vue结尾的文件进行eslint
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
})
module.exports = {
context: path.resolve(__dirname, '../'),
/**
* webpack入口文件
*/
// 修改开始
entry: utils.entries(),
// 修改结束
// webpack输出路径和命名规则
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
// 模块resolve的规则
resolve: {
// 取别名,方便引用模块,例如有了别名之后
// import Vue from 'vue/dist/vue.common.js'可以写成 import Vue from 'vue
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
// 也可以自己添加一些经常引用的路径
'~': resolve('static')
}
},
// 不同类型模块的处理规则
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
// 对所有.vue文件使用vue-loader进行编译
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
// 对所有.js文件使用babel-loader进行编译
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
// 对图片资源文件使用url-loader
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000, // 小于10k 的图片转成base64编码的dataURL字符串写到代码中
name: utils.assetsPath('img/[name].[hash:7].[ext]')// 其他的图片转移到静态资源文件夹
}
},
{
// 对多媒体文件使用url-loader
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
// 对字体资源文件使用url-loader
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// 防止Webpack因为Vue而注入无用的setImmediate polyfill
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
'use strict'
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
//host和端口
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
//dev状态下webpack的一些配置
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
//规则设置是否开启 css 的 sourse map功能,开启了就能很容易定位到某个元素的css的位置
rules: utils.styleLoaders({
sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
//使用cheap-module-eval-source-map作为调试工具
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
//开发状态下的日志等级
clientLogLevel: 'warning',
historyApiFallback: {
rewrites: [
//设置默认主界面
{
from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true, //热重载
contentBase: false, // since we use CopyWebpackPlugin.
compress: true, //当他为true的时候,它会对所有服务器资源采用gzip进行压缩。
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser, //在DevServer第一次构建完成时,自动用浏览器打开网页,默认是true
//该属性是用来在编译出错的时候,在浏览器页面上显示错误
overlay: config.dev.errorOverlay
? {
warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath, //配置项用于打开指定 URL 的网页。
proxy: config.dev.proxyTable, //有一个单独的API后端开发服务器,并且想要在同一个域上发送API请求时,则代理这些 url
quiet: true, // 终端只有启动信息,没有其他的
//监听文件是否有被修改过
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),//热重载
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(), //跳过编译时出错的代码使编译后的代码不会发生错误
// 根据你提供的html模板生成html
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// 添加 FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${
devWebpackConfig.devServer.host}:${
port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})
var path = require('path')
var config = require('../config')
var utils = require('./utils')
var webpack = require('webpack')
var merge = require('webpack-merge')// 一个可以合并数组和对象的插件
var baseWebpackConfig = require('./webpack.base.conf')
// 用于从webpack生成的bundle中提取文本到特定文件中的插件
// 可以抽取出css,js文件将其与webpack输出的bundle分离
var ExtractTextPlugin = require('extract-text-webpack-plugin') //如果我们想用webpack打包成一个文件,css js分离开,需要这个插件
var HtmlWebpackPlugin = require('html-webpack-plugin')// 一个用于生成HTML文件并自动注入依赖文件(link/script)的webpack插件
var env = config.build.env
// 合并基础的webpack配置
var webpackConfig = merge(baseWebpackConfig, {
// 配置样式文件的处理规则,使用styleLoaders
module: {
loaders: utils.styleLoaders({
sourceMap: config.build.productionSourceMap, extract: true })
},
devtool: config.build.productionSourceMap ? '#source-map' : false, // 开启source-map,生产环境下推荐使用cheap-source-map或source-map,后者得到的.map文件体积比较大,但是能够完全还原以前的js代码
output: {
path: config.build.assetsRoot,// 编译输出目录
filename: utils.assetsPath('js/[name].[chunkhash].js'), // 编译输出文件名格式
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') // 没有指定输出名的文件输出的文件名格式
},
vue: {
// vue里的css也要单独提取出来
loaders: utils.cssLoaders({
// css加载器,调用了utils文件中的cssLoaders方法,用来返回针对各类型的样式文件的处理方式,
sourceMap: config.build.productionSourceMap,
extract: true
})
},
// 重新配置插件项
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
// 位于开发环境下
new webpack.DefinePlugin({
'process.env': env
}),
new webpack.optimize.UglifyJsPlugin({
// 丑化压缩代码
compress: {
warnings: false
}
}),
new webpack.optimize.OccurenceOrderPlugin(),
// extract css into its own file
new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), // 抽离css文件
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
// filename 生成网页的HTML名字,可以使用/来控制文件文件的目录结构,最
// 终生成的路径是基于webpac配置的output.path的
new HtmlWebpackPlugin({
// 生成html文件的名字,路径和生产环境下的不同,要与修改后的publickPath相结合,否则开启服务器后页面空白
filename: config.build.index,
// 源文件,路径相对于本文件所在的位置
template: 'index.html',
inject: true,// 要把