启动流程分析
启动入口: 找到package.json 包含工程依赖启动命名直接查找到 "scripts" 下的dev 启动命令,可以看到命令启动了webpack-dev-server 内置的服务,并且执行 build/webpack.dev.conf.js 文件
--progress 命令表示:查看构建过程
--config 表示 自定义配置文件
--inline 自动刷新浏览器
步骤一:
webpack.dev.conf.js 指开发环境部署配置 配置源码分析
'use strict'
//工具方法,主要分辨css预解析器包括:less,sass等,以及合并css到一个主的css文件中
const utils = require('./utils')
const webpack = require('webpack')
//关于webpack 配置文件的输出与开发环境,如端口,静态资源存放路径等。详细查看config/index.js 配置说明
const config = require('../config')
//webpack 工具 大致用于合并两个对象配置
const merge = require('webpack-merge')
const path = require('path')
//关键文件 webpack 编译前端工程的配置,如入口文件地址,输出文件地址,别名,文件预解析器
const baseWebpackConfig = require('./webpack.base.conf')
//webpack 拷贝插件 配置某个起始目录文件拷贝到目标文件中
const CopyWebpackPlugin = require('copy-webpack-plugin')
//webpack 模板配置 配置模板文件预模板输出后的名称 用来资源自动插入
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
//使用merge 合并资源配置 详细配置查看步骤二
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
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,
host: HOST || config.dev.host,//IP 地址
port: PORT || config.dev.port,//端口
open: config.dev.autoOpenBrowser,//是否自动打开浏览器
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,//公用资源路径
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
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(),
// https://github.com/ampedandwired/html-webpack-plugin
//模板插件,自动引入资源到模板中
new HtmlWebpackPlugin({
filename: 'index.html',//设置生成模板的名称
template: './template/index.html',//模板的路径
inject: true //是否自动注入
}),
// copy custom static assets
//拷贝文件插件,获取本地下的static 拷贝到目标文件to中
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
// Add 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)
}
})
})
config/index.js 配置源码分析
'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
//node 自带路径解析工具
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',//静态资源目录
assetsPublicPath: '/',//其他文件工程目录
proxyTable: {},//设置代理
/**
* 代理案例
* proxyTable: {
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
*/
// Various Dev Server settings
host: '0.0.0.0', // 主机IP地址
port: 8080, // 端口
autoOpenBrowser: false,//是否启动自动打开浏览器
errorOverlay: true,
notifyOnErrors: true,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: 'cheap-module-eval-source-map',//编译源码map 目的是为了更快的排错
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
cssSourceMap: true
},
build: {
// Template for index.html
// 构建打包的的文件路径
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
/**
* 这应该指向包含应用程序的所有静态资产的根目录。例如,public/对于Rails / Laravel。
*/
assetsRoot: path.resolve(__dirname, '../dist'),
/**
* 将webpack生成的资源嵌入此目录中
*/
assetsSubDirectory: 'static',
/**
* 这应该是build.assetsRoot通过HTTP提供服务的URL路径。在大多数情况下,这将是root(/)。只有在后端框架为具有路径前缀的静态资产提供服务时才更改此项
*/
assetsPublicPath: '/',
/**
* Source Maps
*/
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}
webpack.base.conf.js 配置源码分析
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js' //入口文件
},
output: {
path: config.build.assetsRoot,//输出路径
filename: '[name].js',//文件名
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath //开发环境输出地址
: config.dev.assetsPublicPath //正式环境输出地址
},
resolve: {
extensions: ['.js', '.vue', '.json'], //扩展文件名结尾
//设置的别名
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'@static':resolve('static'),
'@vuex':resolve('src/vuex'),
'@components':resolve('src/components'),
'@controller':resolve('src/controller'),
'@filters':resolve('src/filters'),
'@directive':resolve('src/directive'),
'@utils':resolve('src/utils'),
'@api':resolve('src/api')
}
},
//预加载器
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig //通过不同环境, loader 选项参数
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// 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'
}
}