Vue
vue-cli2 的配置文件详细介绍
webpack 的运行流程 npm run dev (webpack-dev-server --inline --progress --config build/webpack.dev.conf.js) 在 配置了一些参数 调用 npm run build(node build/build.js) 引入了配置文件,如 npm run dev 流程中的配置文件 调用 webpack.prod.con…
webpack 的运行流程 npm run dev (webpack-dev-server --inline --progress --config build/webpack.dev.conf.js) 在 配置了一些参数 调用 npm run build(node build/build.js) 引入了配置文件,如 npm run dev 流程中的配置文件 调用 webpack.prod.con…
vue2.5webpack3.6开启了单元测试框架jest开启了Eslint检查
webpack.base.conf.js配置了一些参数module.exports = {
context:""
// 配置入口,默认为单页面所以只有app一个入口
entry:{}
// 配置出口
output:{}
// 自动的扩展后缀,创建路径的别名
resolve:{}
// 使用插件配置相应文件的处理方法,设置哪些文件请求哪些解析器
module{}
}
webpack.dev.conf.jsconst baseWebpackConfig = require('./webpack.base.conf')
const devWebpackConfig = merge(baseWebpackConfig, {
// 一些规则工具
module:{},
// 选择一种 source map 格式来增强调试过程
devtool:"",
// 新增配置项
devServer:{},
// 一些插件
plugins{}
})
module.exports = new Promise((resolve, reject) => {
// 缓存端口号
portfinder.basePort = process.env.PORT || config.dev.port
// 查找端口号
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// 设置端口
process.env.PORT = port
// 端口被占用时就重新设置env的端口
devWebpackConfig.devServer.port = port
// 友好地输出信息
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${config.dev.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})
const baseWebpackConfig = require('./webpack.base.conf')
const devWebpackConfig = merge(baseWebpackConfig, {
// 一些规则工具
module:{},
// 选择一种 source map 格式来增强调试过程
devtool:"",
// 新增配置项
devServer:{},
// 一些插件
plugins{}
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
// 提供带 Content-Encoding 编码的压缩版的资源
new CompressionWebpackPlugin({
// 目标资源名称。
// [file] 会被替换成原始资源名称。
// [path] 会被替换成原始资源路径
// [query] 会被替换成原始查询字符串
asset: '[path].gz[query]',
algorithm: 'gzip',
// 处理匹配到的资源
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
// 只处理比这个值大的资源
threshold: 10240,
// 只有压缩率比这个值小的资源才会被处理
minRatio: 0.8
})
)
}
build.js,每次执行都先要删了原来的 build 文件const webpackConfig = require('./webpack.prod.conf');
// 先删除dist文件再生成新文件,因为有时候会使用hash来命名,删除整个文件可避免冗余
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), (err) => {
if (err) throw err;
webpack(webpackConfig, function(err, stats) {
spinner.stop();
if (err) throw err;
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n'
);
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'));
process.exit(1);
}
console.log(chalk.cyan(' Build complete.\n'));
console.log(chalk.yellow(' Tip: built files are meant to be served over an HTTP server.\n' + " Opening index.html over file:// won't work.\n"));
});
});
{
// 项目名称,不能以._开头,不能包含大写字母,不能与现有项目重复
"name": "vue-item",
// 版本号:大版本.次要版本.小版本
"version": "1.0.0",
// 项目描述
"description": "A Vue.js project",
// 作者名字
"author": "dirkhe1051931999 <1051931999@qq.com>",
// 是否私有
"private": true,
// 控制台运行脚本的缩写
"scripts": {
// webpack-dev-server 启动http静态文件服务器,不会刷新浏览器
// 1. webpack-dev-server --inline 前端代码变动的时,刷新浏览器,hash和chunkhash都可以使用
// 2. webpack-dev-server --hot 前端代码变动的时,不刷新浏览器,只把变化的部分替换掉,只能使用hash,如果使用chunkhash会报错
// 3. webpack-dev-server --inline --hot 前端代码变动的时,重新加载改变的部分,HRM失败则刷新页面
// --progress 显示打包进度
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest test/unit/specs --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit/specs",
"build": "node build/build.js"
},
// 项目依赖库:生产环境使用的框架,发布之后还依赖的,比如vue,jq等
"dependencies": {
"vue": "^2.5.2",
"vue-resource": "^1.3.4",
"vue-router": "^3.0.1",
"vuex": "^3.0.1"
},
// 开发依赖库:只是在开发环境依赖的,比如babel-core babel等
"devDependencies": {
//作为postcss插件用来解析css补充前缀,比如display: flex会补充为display:-webkit-box;
"autoprefixer": "^7.1.2",
// babel核心,把js代码解析成AST(抽象语法树)
"babel-core": "^6.22.1",
// 是一个Babel parser的包装器,这个包装器使得Babel parser可以和ESLint协调工作
"babel-eslint": "^7.1.1",
// babel-loader加载器来编译所有的js代码,而无需手动引入babel-core
"babel-loader": "^7.1.1",
// 当你使用 generators/async 函数时,自动引入 babel-runtime/regenerator (使用 regenerator 运行时而不会污染当前环境) 。
// 自动引入 babel-runtime/core-js 并映射 ES6 静态方法和内置插件(实现polyfill的功能且无全局污染,但是实例方法无法正常使用,如 “foobar”.includes(“foo”) )。
// 移除内联的 Babel helper 并使用模块 babel-runtime/helpers 代替(提取babel转换语法的代码)。
// {
// "plugins": [
// ["transform-runtime", {
// "helpers": true, // default
// "polyfill": true, // default
// "regenerator": true, // defalut
// "moduleName": "babel-runtime" // default
// }]
// ]
// }
"babel-plugin-transform-runtime": "^6.22.0",
// 仅仅转换 新版的语法 如:箭头函数,并不转换新版api 如:Array.include
"babel-preset-env": "^1.3.2",
// stage-x分别代表的是stage-0、stage-1、stage-2、stage-3进入EMAC标准之前的4个阶段
"babel-preset-stage-2": "^6.22.0",
// 模块改写require命令,为它加上一个钩子。此后,每当使用require加载.js、.jsx、.es和.es6后缀名的文件,就会先用Babel进行转码。
"babel-register": "^6.22.0",
// 来在命令行输出不同颜色文字
"chalk": "^2.0.1",
// 拷贝资源和文件
"copy-webpack-plugin": "^4.0.1",
// webpack先用css-loader据诶系后缀为css的文件,再使用style-loader,生成最终解析完的css代码的style标签,放入head中
"css-loader": "^0.28.0",
// 一些开启语法检测的插件
"eslint": "^3.19.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-html": "^3.0.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-promise": "^3.4.0",
"eslint-plugin-standard": "^3.0.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.2.0",
"eventsource-polyfill": "^0.9.6",
//将一个以上的包里面的文本提取到单独文件中
"extract-text-webpack-plugin": "^3.0.0",
// 打包压缩文件,与url-loader用法类似
"file-loader": "^1.1.4",
// 识别某些类别的webpack错误和清理,聚合和优先排序,以提供更好的开发经验
"friendly-errors-webpack-plugin": "^1.6.1",
// 简化了HTML文件的创建,引入了外部资源,创建html的入口文件,可通过此项进行多页面的配置
"html-webpack-plugin": "^2.30.1",
// 可视化webpack输出文件的大小
"webpack-bundle-analyzer": "^2.9.0",
"babel-jest": "^21.0.2",
"jest": "^21.2.0",
"vue-jest": "^1.0.2",
// 支持使用node发送跨平台的本地通知
"node-notifier": "^5.1.2",
//可以消耗本地文件、节点模块或web_modules
"postcss-import": "^11.0.0",
//用来兼容css的插件
"postcss-loader": "^2.0.8",
//用来对特定的版本号做判断的
"semver": "^5.3.0",
// 使用它来消除shell脚本在UNIX上的依赖性,同时仍然保留其熟悉和强大的命令,即可执行Unix系统命令
"shelljs": "^0.7.6",
// 压缩提取出的css,并解决ExtractTextPlugin分离出的js重复问题(多个文件引入同一css文件)
"optimize-css-assets-webpack-plugin": "^3.2.0",
// 实现node.js 命令行环境的 loading效果, 和显示各种状态的图标等
"ora": "^1.2.0",
// 节点的UNIX命令RM—RF,强制删除文件或者目录的命令
"rimraf": "^2.6.0",
// 压缩文件,可将图片转化为base64
"url-loader": "^0.5.8",
// 编译.vue的文件,打包成浏览器认识的js代码
"vue-loader": "^13.3.0",
// 检查这个组件是否已经具有服务器内联(server-inlined)的 CSS - 如果没有,CSS 将通过 <style> 标签动态注入。
"vue-style-loader": "^3.0.1",
// 这个包可以用来预编译VUE模板到渲染函数,以避免运行时编译开销和CSP限制
"vue-template-compiler": "^2.5.2",
// 是用来查看端口是否被占用
"portfinder": "^1.0.13",
"webpack": "^3.6.0",
//提供一个提供实时重载的开发服务器
"webpack-dev-server": "^2.9.1",
// 将数组和合并对象创建一个新对象
"webpack-merge": "^4.1.0"
},
// 自动化测试之前端js单元测试框架jest
"jest": {
"moduleFileExtensions": ["js", "json", "vue"],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
},
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"setupFiles": ["<rootDir>/test/unit/setup"],
"mapCoverage": true,
"coverageDirectory": "<rootDir>/test/unit/coverage",
"collectCoverageFrom": ["src/**/*.{js,vue}", "!src/main.js", "!src/router/index.js", "!**/node_modules/**"]
},
//engines是引擎,指定node和npm版本
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
//限制了浏览器或者客户端需要什么版本才可运行
"browserslist": ["> 1%", "last 2 versions", "not ie <= 8"]
}
该文件是 es6 解析的一个配置
{
// 制定转码的规则
"presets": [
// env是使用babel-preset-env插件将js进行转码成es5
// 设置不转码的AMD,common的模块文件
["env", {
"modules": false
}],
"stage-2"
],
"plugins": ["transform-runtime"],
"env": {
"test": {
"presets": ["env", "stage-2"] }
}
}
编辑器的配置文件
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
.postcssrc.js 文件其实是 postcss-loader 包的一个配置,里面写进去需要使用到的插件
module.exports = {
plugins: {
// to edit target browsers: use "browserslist" field in package.json
'postcss-import': {},
autoprefixer: {}
}
};
config 内的文件其实是服务于 build 的,大部分是定义一个变量 export 出去
// 合并函数
const merge = require('webpack-merge');
const prodEnv = require('./prod.env');
// 可以将数据和对象合并,最终合并成为一个对象,如果有数组,那么对象的key就是数组的索引
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
});
在 webpack 压缩的时候配置的参数文件
const path = require('path');
module.exports = {
// 开发环境下面的配置
dev: {
// 子目录,一般存放css,js,image等文件
assetsSubDirectory: 'static',
// 根目录
assetsPublicPath: '/',
// 可利用该属性解决跨域的问题
proxyTable: {},
// 地址
host: 'localhost',
// 端口
port: 8080,
// 是否在浏览器中自动打开页面
autoOpenBrowser: false,
// 浏览器错误提示
errorOverlay: true,
// 跨平台错误提示
notifyOnErrors: true,
// 使用文件系统(file system)获取文件改动的通知devServer.watchOptions
poll: false,
// Eslit的配置
useEslint: false,
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// 增加调试,该属性为原始源代码(仅限行)不可在生产环境中使用
devtool: 'eval-source-map',
// 使缓存失效
cacheBusting: true,
// 记录压缩前后的位置信息记录,当产生错误时直接定位到未压缩前的位置
cssSourceMap: false
},
// 生产环境下面的配置
build: {
// index编译后生成的位置和名字
index: path.resolve(__dirname, '../dist/index.html'),
// 编译后存放生成环境代码的位置
assetsRoot: path.resolve(__dirname, '../dist'),
// js,css,images存放文件夹名
assetsSubDirectory: 'static',
// 发布的根目录
assetsPublicPath: '/',
// 打包后要不要的.map文件
productionSourceMap: true,
// 选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度
devtool: '#source-map',
// unit的gzip命令用来压缩文件,gzip模式下需要压缩的文件的扩展名有js和css
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// 在打包的时候输入npm run build --report,就可以在打包的同时查看每个打包生成的js,里面的库的构成情况,
// 方便我们进行相关的删减,比如有的库太大了,是否可以自己实现,有的库是否有必要,可否删除之类。
bundleAnalyzerReport: process.env.npm_config_report
}
};
当开发时调取 dev.env.js 的开发环境配置,发布时调用 prod.env.js 的生产环境配置
// 当开发时调取dev.env.js的开发环境配置,发布时调用prod.env.js的生产环境配置
module.exports = {
NODE_ENV: '"production"'
};
构建生产版本
// 执行检查版本,有问题会报警告
require('./check-versions')();
// 设置当前是生产环境
process.env.NODE_ENV = 'production';
// 实现node.js 命令行环境的 loading效果, 和显示各种状态的图标等
const ora = require('ora');
// 节点的UNIX命令RM—RF,强制删除文件或者目录的命令
const rm = require('rimraf');
const path = require('path');
// 来在命令行输出不同颜色文字
const chalk = require('chalk');
const webpack = require('webpack');
// 默认读取下面的index.js文件
const config = require('../config');
const webpackConfig = require('./webpack.prod.conf');
// 调用start的方法实现加载动画,优化用户体验
const spinner = ora('building for production...');
spinner.start();
// 先删除dist文件再生成新文件,因为有时候会使用hash来命名,删除整个文件可避免冗余
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), (err) => {
if (err) throw err;
webpack(webpackConfig, function(err, stats) {
spinner.stop();
if (err) throw err;
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n'
);
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'));
process.exit(1);
}
console.log(chalk.cyan(' Build complete.\n'));
console.log(chalk.yellow(' Tip: built files are meant to be served over an HTTP server.\n' + " Opening index.html over file:// won't work.\n"));
});
});
用于检测 node 和 npm 的版本,实现版本依赖
// 来在命令行输出不同颜色文字
const chalk = require('chalk');
// 用来对特定的版本号做判断的
const semver = require('semver');
// 导入package.json文件
const packageConfig = require('../package.json');
// 使用它来消除shell脚本在UNIX上的依赖性,同时仍然保留其熟悉和强大的命令,即可执行Unix系统命令
const shell = require('shelljs');
function exec(cmd) {
// 通过child_process模块的新建子进程
// 进而执行 Unix 系统命令后转成没有空格的字符串
return require('child_process')
.execSync(cmd)
.toString()
.trim();
}
// 把格式化的版本缓存下来
const versionRequirements = [
{
name: 'node',
//使用semver格式化版本
currentVersion: semver.clean(process.version),
// 获取package.json中设置的node版本
versionRequirement: packageConfig.engines.node
}
];
// 判定npm命令是否可用
if (shell.which('npm')) {
// 自动调用npm --version命令,并且把参数返回给exec函数,从而获取纯净的版本号
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
});
}
module.exports = function() {
// 把警告缓存下来
const warnings = [];
// 遍历一下缓存的版本
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i];
// 如果版本号不符合package.json文件中指定的版本号,就执行下面错误提示的代码
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement));
}
}
// 如果警告存在,就依次打印出来
if (warnings.length) {
console.log('');
console.log(chalk.yellow('To use this template, you must update following to modules:'));
console.log();
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i];
console.log(' ' + warning);
}
console.log();
process.exit(1);
}
};
主要有 1.cssLoaders: 用于加载.vue 文件中的样式和 2.styleLoaders:对.vue 文件之外的 css 文件或 css 预处理器文件进行处理
'use strict';
const path = require('path');
// 默认读取下面的index.js文件
const config = require('../config');
// 将一个以上的包里面的文本提取到单独文件中
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// 导入package.json文件
const pkg = require('../package.json');
// 根据环境判断开发环境和生产环境,进而返回是生产环境的静态资源目录,还是开发环境的静态资源目录
exports.assetsPath = function(_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory;
// path.posix,提供对路径方法的可移植性操作系统接口,特定实现的访问
// path.join:用于连接路径,会正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是""
return path.posix.join(assetsSubDirectory, _path);
};
// 用于加载.vue文件中的样式
exports.cssLoaders = function(options) {
options = options || {};
// cssloader
const cssLoader = {
loader: 'css-loader',
// loader的选项配置
options: {
//生成环境下压缩文件
minimize: process.env.NODE_ENV === 'production',
// 根据参数是否生成sourceMap文件
sourceMap: options.sourceMap
}
};
// postcssLoader
var postcssLoader = {
loader: 'postcss-loader',
options: {
// 根据参数是否生成sourceMap文件
sourceMap: options.sourceMap
}
};
// generate loader string to be used with extract text plugin
function generateLoaders(loader, loaderOptions) {
// 选择默认loader
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader];
// 如果有css预处理器文件(如less、sass、stylus等)
if (loader) {
loaders.push({
// 使用该预处理器对应的加载器
loader: loader + '-loader',
// 将css加载器初始配置与该预处理器的特殊配置进行合并
options: Object.assign({}, loaderOptions, {
// 根据参数是否生成sourceMap文件
sourceMap: options.sourceMap
})
});
}
// 是否将入口文件(main.js)中引入的css文件一起打包进该文件的css中
// 根据传入的options.extract的值进行判断(一般在生产环境中会去单独打包)
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')
};
};
// 对.vue文件之外的css文件或css预处理器文件进行处理
exports.styleLoaders = function(options) {
const output = [];
const loaders = exports.cssLoaders(options);
// 遍历cssLoaders返回出来的所有文件类型
for (const extension in loaders) {
const loader = loaders[extension];
// 对每一个文件类型用其相对应的加载器进行处理
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
});
}
return output;
};
// 是一个跨平台系统通知的页面,当遇到错误时,它能用系统原生的推送方式给你推送信息
// 就是编辑器右上角的警告通知
exports.createNotifierCallback = function() {
const notifier = require('node-notifier');
return (severity, errors) => {
if (severity !== 'error') {
return;
}
const error = errors[0];
const filename = error.file.split('!').pop();
notifier.notify({
title: pkg.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
// 这个右上角警告的那个图片
icon: path.join(__dirname, 'logo.png')
});
};
};
该文件的主要作用就是处理.vue 文件,解析这个文件中的每个语言块(template、script、style),转换成 js 可用的 js 模块
// 获取到公共方法
const utils = require('./utils');
// 获取到配置文件,默认访问index
const config = require('../config');
// 获取到当前环境
const isProduction = process.env.NODE_ENV === 'production';
// 打包后要不要的.map文件
const sourceMapEnabled = isProduction ? config.build.productionSourceMap : config.dev.cssSourceMap;
module.exports = {
// 处理项目中的css文件,生产环境和测试环境默认是打开sourceMap
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
// 提取样式到单独文件只有在生产环境中才需要
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
// 在模版编译过程中,编译器可以将某些属性,如 src 路径,转换为require调用,以便目标资源可以由 webpack 处理
transformToRequire: {
video: 'src',
source: 'src',
img: 'src',
image: 'xlink:href'
}
};
webpack.base.conf.js 是开发和生产共同使用提出来的基础配置文件,主要实现配制入口,配置输出环境,配置模块 resolve 和插件等
const path = require('path');
// 获取到公共方法
const utils = require('./utils');
// 获取到配置文件,默认访问index
const config = require('../config');
// 获取到当前环境
const vueLoaderConfig = require('./vue-loader.conf');
//拼接出绝对路径
function resolve(dir) {
return path.join(__dirname, '..', dir);
}
module.exports = {
// 而path.resolve将以/开始的路径片段作为根目录,在此之前的路径将会被丢弃
// path.join('/a', '/b')
// path.resolve('/a', '/b')
// 等于'/b'
context: path.resolve(__dirname, '../'),
// 配置入口,默认为单页面所以只有app一个入口
entry: {
app: './src/main.js'
},
// 配置出口,
output: {
// 默认是/dist作为目标文件夹的路径
path: config.build.assetsRoot,
//文件名
filename: '[name].js',
// 静态文件的路径,根据生成环境判断
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
},
resolve: {
// 自动的扩展后缀,比如一个js文件,则引用时书写可不要写.js
extensions: ['.js', '.vue', '.json'],
// 创建路径的别名
alias: {
vue$: 'vue/dist/vue.esm.js',
'@': resolve('src')
}
},
module: {
// 使用插件配置相应文件的处理方法
rules: [
// ESlint的报错提示
...(config.dev.useEslint
? [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
}
]
: []),
// 使用vue-loader将vue文件转化成js的模块
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
// js文件需要通过babel-loader进行编译成es5文件以及压缩等操作
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
// 图片、音像、字体都使用url-loader进行处理,超过10000b会编译成base64
{
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]')
}
}
]
}
};
// 引入公共模块
const utils = require('./utils');
// 导入webpack
const webpack = require('webpack');
// 导入配置
const config = require('../config');
// 可以将数据和对象合并,最终合并成为一个对象,如果有数组,那么对象的key就是数组的索引
const merge = require('webpack-merge');
// 引入基础文件
const baseWebpackConfig = require('./webpack.base.conf');
// 简化了HTML文件的创建,引入了外部资源,创建html的入口文件,可通过此项进行多页面的配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 识别某些类别的webpack错误和清理,聚合和优先排序,美化webpack的错误信息和日志的插件
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
// 是用来查看端口是否被占用
const portfinder = require('portfinder');
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
// 规则是工具utils中处理出来的styleLoaders,生成了css,less,postcss等规则
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// 选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度
devtool: config.dev.devtool,
// 此处的配置都是在config的index.js中设定好了
devServer: {
// 控制台显示的选项有none, error, warning 或者 info
clientLogLevel: 'warning',
// 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html
// 比如History.back()
historyApiFallback: true,
//热加载
hot: true,
host: process.env.HOST || config.dev.host,
port: process.env.PORT || config.dev.port,
//调试时自动打开浏览器,这个默认是false
open: config.dev.autoOpenBrowser,
// warning 和 error 都要显示,这个默认是true
overlay: config.dev.errorOverlay
? {
warnings: false,
errors: true
}
: false,
// 发布的根目录
publicPath: config.dev.assetsPublicPath,
// 接口代理
proxy: config.dev.proxyTable,
// 控制台是否禁止打印警告和错误,若用FriendlyErrorsPlugin 此处为 true
quiet: true,
// 文件系统检测改动
watchOptions: {
poll: config.dev.poll
}
},
plugins: [
// 允许创建一个在编译时可以配置的全局常量
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
// 模块热替换插件,修改模块时不需要刷新页面
new webpack.HotModuleReplacementPlugin(),
// 显示文件的正确名字
new webpack.NamedModulesPlugin(),
// 当webpack编译错误的时候,来中断打包进程,防止错误代码打包到文件中
new webpack.NoEmitOnErrorsPlugin(),
// 可以让插件自动生成一个HTML文件
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
});
module.exports = new Promise((resolve, reject) => {
// 缓存端口号
portfinder.basePort = process.env.PORT || config.dev.port;
// 查找端口号
portfinder.getPort((err, port) => {
if (err) {
reject(err);
} else {
// 设置端口
process.env.PORT = port;
// 端口被占用时就重新设置env的端口
devWebpackConfig.devServer.port = port;
// 友好地输出信息
devWebpackConfig.plugins.push(
new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${config.dev.host}:${port}`]
},
onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined
})
);
resolve(devWebpackConfig);
}
});
});
const path = require('path');
// 引入公共方法
const utils = require('./utils');
const webpack = require('webpack');
// 引入配置文件
const config = require('../config');
// 可以将数据和对象合并,最终合并成为一个对象,如果有数组,那么对象的key就是数组的索引
const merge = require('webpack-merge');
// 引入基础文件
const baseWebpackConfig = require('./webpack.base.conf');
// 拷贝资源和文件
const CopyWebpackPlugin = require('copy-webpack-plugin');
// 可自动创建一个index.html文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 将一个以上的包里面的文本提取到单独文件中
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// 压缩提取出的css,并解决ExtractTextPlugin分离出的js重复问题(多个文件引入同一css文件)
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
// 先确定环境
const env = process.env.NODE_ENV === 'testing' ? require('../config/test.env') : require('../config/prod.env');
const webpackConfig = merge(baseWebpackConfig, {
module: {
// 调用utils.styleLoaders的方法
rules: utils.styleLoaders({
// 打包后要不要的.map文件
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
// 如果要map文件,择一种 source map 格式来增强调试过程
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
// 静态资源的位置
path: config.build.assetsRoot,
// js名字
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[name].[chunkhash].js')
},
plugins: [
// 许创建一个在编译时可以配置的全局常量
new webpack.DefinePlugin({
'process.env': env
}),
// 压缩js的,但是不支持es6代码的压缩
new webpack.optimize.UglifyJsPlugin({
// uglifyjs是否看到的警告信息
compress: {
warnings: false
},
// 是否需要map文件,已经在config中设置了
sourceMap: config.build.productionSourceMap,
//
parallel: true
}),
// 抽取文本。比如打包之后的index页面有style插入,就是这个插件抽取出来的,减少请求
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
allChunks: false
}),
// 优化css的插件
// 优化、最小化css代码,如果只简单使用extract-text-plugin可能会造成css重复
new OptimizeCSSPlugin({
// 打包后要不要的.map文件
cssProcessorOptions: config.build.productionSourceMap
? {
// 避免 cssnano 重新计算 z-index
safe: true,
// map文件的行内样式
map: {
inline: false
}
}
: {
// 避免 cssnano 重新计算 z-index
safe: true
}
}),
// html打包
new HtmlWebpackPlugin({
// 判断是哪个环境
filename:
process.env.NODE_ENV === 'testing'
? 'index.html'
: // 访问build后的index.html
config.build.index,
template: 'index.html',
// 向template或者templateContent中注入所有静态资源,不同的配置值注入的位置不经相同
inject: true,
//压缩
minify: {
//删除注释
removeComments: true,
//删除空格
collapseWhitespace: true,
//删除属性的引号
removeAttributeQuotes: true
},
// 模块排序,按照我们需要的顺序排序
chunksSortMode: 'dependency'
}),
// 是用于保持模块引用的 module id 不变
new webpack.HashedModuleIdsPlugin(),
// 过去 webpack 打包时的一个取舍是将 bundle 中各个模块单独打包成闭包。这些打包函数使你的 JavaScript 在浏览器中处理的更慢
// 可以提升(hoist)或者预编译所有模块到一个闭包中,提升你的代码在浏览器中的执行速度。
new webpack.optimize.ModuleConcatenationPlugin(),
// 通过将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,便存到缓存中供后续使用。
// 这个带来页面速度上的提升,因为浏览器会迅速将公共的代码从缓存中取出来,
// 而不是每次访问一个新页面时,再去加载一个更大的文件。
new webpack.optimize.CommonsChunkPlugin({
// 可以是已经存在的chunk(一般指入口文件)对应的name,那么就会把公共模块代码合并到这个chunk上
// 否则,会创建名字为name的commons chunk进行合并
name: 'vendor',
// filename:指定commons chunk的文件名
// 既可以是数字,也可以是函数,还可以是Infinity
minChunks: function(module) {
// any required modules inside node_modules are extracted to vendor
// 数字:模块被多少个chunk公共引用才被抽取出来成为commons chunk
// 函数:接受 (module, count) 两个参数,返回一个布尔值,你可以在函数内进行你规定好的逻辑来决定某个模块是否提取成为commons chunk
// Infinity:只有当入口文件(entry chunks) >= 3 才生效,用来在第三方库中分离自定义的公共模块
// 从node_modules抽取到需要的module,生成vendor.js
return module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0;
}
}),
/**
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor', 'runtime'],
filename: '[name].js',
minChunks: Infinity
}),
等同于
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
filename: '[name].js',
chunks: ['vendor']
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
filename: '[name].js',
chunks: ['first', 'second'] //从first.js和second.js中抽取commons chunk
}),
查看dist目录下,新增了一个common.js的文件
*/
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
// 用来在第三方库中分离自定义的公共模块,生成manifest.js
minChunks: Infinity
}),
// 这两个属性主要是在code split(代码分割)和异步加载当中应用
new webpack.optimize.CommonsChunkPlugin({
// 进行code split出来的childrend的chunks,生成app.js
name: 'app',
async: 'vendor-async',
// 为true所有公共 chunk 的子模块都会被选择
children: true,
minChunks: 3
}),
// 如打包完之后需要把打包的文件复制到dist里面
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
});
// 是否开启GZIP
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin');
webpackConfig.plugins.push(
// 提供带 Content-Encoding 编码的压缩版的资源
new CompressionWebpackPlugin({
// 目标资源名称。
// [file] 会被替换成原始资源名称。
// [path] 会被替换成原始资源路径
// [query] 会被替换成原始查询字符串
asset: '[path].gz[query]',
algorithm: 'gzip',
// 处理匹配到的资源
test: new RegExp('\\.(' + config.build.productionGzipExtensions.join('|') + ')$'),
// 只处理比这个值大的资源
threshold: 10240,
// 只有压缩率比这个值小的资源才会被处理
minRatio: 0.8
})
);
}
// 在打包的时候输入npm run build --report,就可以在打包的同时查看每个打包生成的js,里面的库的构成情况
if (config.build.bundleAnalyzerReport) {
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
module.exports = webpackConfig;
暂无评论
确认操作
请再次确认编辑图片
待上传图片 (剩余 0 张)
项目详情
确认评论邮箱
邀请制评论