文件目录
build.js
check-versions.js
logo.png
vue-loader.conf.js
webpack.base.conf.js
webpack.dev.conf.js
webpack.dll.conf.js
webpack.prod.conf.js
build.js
"use strict";
require("./check-versions")();
process.env.NODE_ENV = "production";
/**
* @description: 用于node的控制台进度美化
*/
const ora = require("ora");
/**
* @description: 插件介绍
* 使用webpack build文件项目时每次都会生成一个dist目录,有时需要把dist目录里的所以旧文件全部删掉,除了可以使用rm -rf /dist/命令删除外,还可以使用rimraf /dist/命令;
* rimraf 的作用:以包的形式包装rm -rf命令,用来删除文件和文件夹的,不管文件夹是否为空,都可删除;
*/
const rm = require("rimraf");
/**
* @description: Node.js path 模块提供了一些用于处理文件路径的小工具,我们可以通过以下方式引入该模块:
* 详解:https://www.runoob.com/nodejs/nodejs-path-module.html
*/
const path = require("path");
/**
* @description: 用于控制台输出美化
* chalk 包的作用是修改控制台中字符串的样式,包括:
* 字体样式(加粗、隐藏等)
* 字体颜色
* 背景颜色
*/
const chalk = require("chalk");
const webpack = require("webpack");
/**
* @description: //引入config 文件夹下暴露出来的对象 (三个文件这里都引入了)
*/
const config = require("../config");
const webpackConfig = require("./webpack.prod.conf");
const spinner = ora("building for production...");//生产模式打包中……
spinner.start();
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err;
webpack(webpackConfig, (err, stats) => {
spinner.stop();
if (err) throw err;
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false, // 如果您使用 ts-loader,将其设置为 true 将使构建期间出现 TypeScript 错误。
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"
)
);//提示:构建的文件旨在通过 HTTP 服务器提供服务。\n" + " 通过 file:// 打开 index.html 将不起作用。\n"
});
});
check-versions.js
'use strict'
/**
* @description: chalk 包的作用是修改控制台中字符串的样式,包括:
* 字体样式(加粗、隐藏等)
* 字体颜色
* 背景颜色
*/
const chalk = require('chalk')
/**
* @description: 同时也可以作为一个命令行工具。功能包括:
* 比较两个版本号的大小
* 验证某个版本号是否合法
* 提取版本号,例如从“=v1.2.1”体取出"1.2.1"
* 分析版本号是否属于某个范围或符合一系列条件
* 等等
*/
const semver = require('semver')
const packageConfig = require('../package.json')
/**
* @description: ShellJS 是基于Node.js API 的 Unix shell 命令的可移植(Windows/Linux/macOS)实现。您可以使用它来消除您的 shell 脚本对 Unix 的依赖,同时仍然保留其熟悉而强大的命令。您还可以全局安装它,以便您可以从 Node 项目外部运行它 - 告别那些粗糙的 Bash 脚本!
*/
const shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
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]
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)
}
}
utils.js
'use strict'
const path = require('path')
const config = require('../config')
/**
* @description: extract-text-webpack-plugin基本参数说明: 用法说明:用于提取css成独立文件
* filename:生成文件的文件名,可以包含 [name], [id], [contenthash]
* allChunks:当为false的时候,只会提取初始化的时候引入的css,当allChunks属性为true时,会把异步引入的css也提取出来。
* ExtractTextPlugin.extract基本参数说明:
* use:指需要什么样的loader去编译文件
* fallback: 这里表示不提取的时候,使用什么样的配置来处理css
* publicfile:用来覆盖项目路径,生成该css文件的文件路径
*
*/
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)
}
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
})
})
}
// 指定该选项时提取 CSS
//(这是生产构建期间的情况)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader',
publicPath: '../../', //解决ele小图标出不来问题
})
} 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 之外)
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
}
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')
})
}
}
vue-loader.conf.js
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
webpack.base.conf.js
"use strict";
const path = require("path");
const utils = require("./utils");
const config = require("../config");
const vueLoaderConfig = require("./vue-loader.conf");
const webpack = require("webpack");
// const manifest = require('../vendor-manifest.json')
// const manifesttwo = require('../vendortwo-manifest.json')
// const manifestthree = require('../vendorthree-manifest.json')
/**
* @description: 压缩图片插件
*/
const ImageminPlugin = require("imagemin-webpack-plugin").default;
function resolve(dir) {
return path.join(__dirname, "..", dir);
}
module.exports = {
externals: {
vue: "Vue"
// 'echarts': 'echarts',
// 'element-ui': 'ElementUI',
// 'v-charts': 'VCharts',
// 'vue-quill-editor': 'VueQuillEditor',
},
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")
}
},
plugins: [
new ImageminPlugin({
disable: process.env.NODE_ENV !== 'production', // Disable during development
pngquant: {
quality: '95-100'
}
}),
// new webpack.DllReferencePlugin({
// manifest:manifest
// }),
// new webpack.DllReferencePlugin({
// manifest: manifesttwo
// }),
// new webpack.DllReferencePlugin({
// manifest: manifestthree
// }),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
// jquery: "jquery",
"window.jQuery": "jquery"
// 'window.Quill': 'quill/dist/quill.js',
// 'Quill': 'quill/dist/quill.js'
})
],
context: path.resolve(__dirname, "../"),
entry: {
// app: './src/main.js'
app: ["babel-polyfill", "./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")
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: "babel-loader",
include: [
resolve("src"),
resolve("test"),
resolve("node_modules/webpack-dev-server/client"),
resolve("node_modules/element-china-area-data"),
resolve("node_modules")
],
exclude: /node_modules/
},
{
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: {
// 防止 webpack 注入无用的 setImmediate polyfill 因为 Vue
// source 包含它(尽管只有在它是本机时才使用它)。
setImmediate: false,
// 防止 webpack 将模拟注入 Node 原生模块
// 这对客户端没有意义
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty"
}
};
webpack.dev.conf.js
"use strict";
const utils = require("./utils");
/**
* @description: 引入的webpack
*/
const webpack = require("webpack");
const config = require("../config");
const merge = require("webpack-merge");
const path = require("path");
const baseWebpackConfig = require("./webpack.base.conf");
/**
* @description: 插件的作用是将项目中的某单个文件或整个文件夹在打包的时候复制一份到打包后的文件夹中(即复制一份到dist目录下)。”
*/
const CopyWebpackPlugin = require("copy-webpack-plugin");
/**
* @description: html-webpack-plugin说明:
为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题
可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口
*/
const HtmlWebpackPlugin = require("html-webpack-plugin");
/**
* @description: 优化webpack的控制台输出
*/
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin");
/**
* @description: 帮你自动获取可用端口
*/
const portfinder = require("portfinder");
const HOST = process.env.HOST;
const PORT = process.env.PORT && Number(process.env.PORT);
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.dev.cssSourceMap,
usePostCSS: true
})
},
//cheap-module-eval-source-map 开发速度更快
devtool: config.dev.devtool,
// 这些 devServer 选项应该在 /config/index.js 中自定义
devServer: {
clientLogLevel: "warning",
historyApiFallback: {
rewrites: [
{
from: /.*/,
to: path.posix.join(config.dev.assetsPublicPath, "index.html")
}
]
},
hot: true,
// inline: false, // 关闭热更新
contentBase: false, // 因为我们使用 CopyWebpackPlugin。
compress: true,
host: HOST || config.dev.host,
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, // 对于 FriendlyErrorsPlugin 是必需的
watchOptions: {
poll: config.dev.poll
}
},
plugins: [
new webpack.DefinePlugin({
"process.env": require("../config/dev.env")
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR 在更新时在控制台中显示正确的文件名
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: "index.html",
template: "index.html",
inject: true
}),
// 复制自定义静态资源
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 {
// 发布新的端口,e2e 测试所必需的
process.env.PORT = port;
// 将端口添加到 devServer 配置
devWebpackConfig.devServer.port = port;
// 添加友好错误插件
devWebpackConfig.plugins.push(
new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [
`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`
]
},
one rrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
})
);
resolve(devWebpackConfig);
}
});
});
webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
//填写需要提取出来的依赖包
//如果有些依赖包在index.html页面引入了cdn了就无需再引入了,否则会打包进js文件中,在页面重复引入代码。
// vendor: ['element-ui'],
// vendortwo: ['v-charts'],
// vendorthree: ['vue-quill-editor'],
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
output: {
path: path.join(__dirname, '../static'),
filename: 'dll.[name].js',
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, '../', '[name]-manifest.json'),
name: '[name]'
})
]
}
webpack.prod.conf.js
"use strict";
const path = require("path");
const utils = require("./utils");
/**
* @description: 引入的webpack
*/
const webpack = require("webpack");
/**
* @description: //引入config 文件夹下暴露出来的对象 (三个文件这里都引入了)
*/
const config = require("../config");
// console.log(config);
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
/**
* @description: 插件的作用是将项目中的某单个文件或整个文件夹在打包的时候复制一份到打包后的文件夹中(即复制一份到dist目录下)。”
*/
const CopyWebpackPlugin = require("copy-webpack-plugin");
/**
* @description: html-webpack-plugin说明:
为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题
可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口
*/
const HtmlWebpackPlugin = require("html-webpack-plugin");
/**
* @description: extract-text-webpack-plugin基本参数说明: 用法说明:用于提取css成独立文件
* filename:生成文件的文件名,可以包含 [name], [id], [contenthash]
* allChunks:当为false的时候,只会提取初始化的时候引入的css,当allChunks属性为true时,会把异步引入的css也提取出来。
* ExtractTextPlugin.extract基本参数说明:
* use:指需要什么样的loader去编译文件
* fallback: 这里表示不提取的时候,使用什么样的配置来处理css
* publicfile:用来覆盖项目路径,生成该css文件的文件路径
*
*/
const ExtractTextPlugin = require("extract-text-webpack-plugin"); //在webpack4中,建议用mini-css-extract-plugin替代
/**
* @description: 此插件实现压缩css
*/
const OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin");
/**
* @description: 此插件使用uglify-js进行js文件的压缩。
*/
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const env = require("../config/prod.env");
const webpackConfig = merge(baseWebpackConfig, {
module: {
////config.build.productionSourceMap 值为 false或者true 禁止打包后生成.map文件 --可以防止生产环境源码的暴露 减小打包后文件体积
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
//config.build.productionSourceMap 值为 false或者true 禁止打包后生成.map文件 --可以防止生产环境源码的暴露 减小打包后文件体积
//config.build.devtool: "#source-map",
//chunkhash 作用 生成唯一哈希值 当修改的某些文件后相应涉及到的地方的哈希值才做改变,没有涉及到的不修改(改了一处地方不用全局刷新了,相应模块的刷新)
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot, //相当于 path:path.resolve(__dirname, "../dist"),
filename: utils.assetsPath("js/[name].[chunkhash].js"),
chunkFilename: utils.assetsPath("js/[id].[chunkhash].js")
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
"process.env": env
}),
// 安装uglifyjs-webpack-plugin 去除console来减少文件大小
// cnpm install uglifyjs-webpack-plugin --save-dev
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false,
//drop_console 传递true以放弃对控制台的调用。*功能
drop_console: true,
// pure_funces 禁用console.log函数
pure_funcs: ["console.log"]
}
},
sourceMap: config.build.productionSourceMap, //config.build.productionSourceMap 值为 false或者true 禁止打包后生成.map文件 --可以防止生产环境源码的暴露 减小打包后文件体积
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath("css/[name].[contenthash].css"),
// 将以下选项设置为 `false` 将不会从代码拆分块中提取 CSS。
// 当 webpack 加载 codesplit 块时,它们的 CSS 将改为使用 style-loader 动态插入。
// 当前设置为 `true` 因为我们看到 sourcemaps 也包含在 codesplit bundle 中,当它为 `false` 时,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: false
}),
// 压缩提取的 CSS。 我们正在使用这个插件,以便可能
// 可以删除来自不同组件的重复 CSS。
//config.build.productionSourceMap 值为 false或者true 禁止打包后生成.map文件 --可以防止生产环境源码的暴露 减小打包后文件体积
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// 生成带有正确资产哈希的 dist index.html 用于缓存。
// 您可以通过编辑 /index.html 自定义输出
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index, //相当于: filename:path.resolve(__dirname, "../dist/index.html"),
template: "index.html",
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: "dependency"
}),
// 当供应商模块没有改变时保持 module.id 稳定
new webpack.HashedModuleIdsPlugin(),
// 启用范围提升
new webpack.optimize.ModuleConcatenationPlugin(),
// 将 vendor js 拆分成自己的文件
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks(module) {
// node_modules 中的任何必需模块都被提取到供应商
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, "../node_modules")) === 0
);
}
}),
// 将 webpack 运行时和模块清单提取到它自己的文件中,以便
// 每当应用程序包更新时,防止供应商哈希值更新
new webpack.optimize.CommonsChunkPlugin({
name: "manifest",
minChunks: Infinity
}),
// 此实例从代码拆分的块中提取共享块并捆绑它们
// 在一个单独的块中,类似于供应商块
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: "app",
async: "vendor-async",
children: true,
minChunks: 3
}),
// 复制自定义静态资源
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, "../static"),
to: config.build.assetsSubDirectory, // 相当于 to:"static",
ignore: [".*"]
}
])
]
});
//如果开启了gzip压缩 就执行以下代码
if (config.build.productionGzip) {
/**
* @description: 实现Gzip压缩
* @param {*}
* @return {*}
*/
const CompressionWebpackPlugin = require("compression-webpack-plugin");
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: new RegExp(
"\\.(" + config.build.productionGzipExtensions.join("|") + ")$"
), //相当于 : test: new RegExp("\\.(" + ["js", "css"].join("|") + ")$")
//相当于 : test: new RegExp("\\.(js|css)$")
threshold: 10240,
minRatio: 0.8
})
);
}
// 是否开启打包后的分析报告
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}
module.exports = webpackConfig;