New file |
| | |
| | | 'use strict' |
| | | require('./check-versions')() |
| | | |
| | | process.env.NODE_ENV = 'production' |
| | | |
| | | const ora = require('ora') |
| | | const rm = require('rimraf') |
| | | const path = require('path') |
| | | const chalk = require('chalk') |
| | | const webpack = require('webpack') |
| | | 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, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. |
| | | 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' |
| | | )) |
| | | }) |
| | | }) |
New file |
| | |
| | | 'use strict' |
| | | const chalk = require('chalk') |
| | | const semver = require('semver') |
| | | const packageConfig = require('../package.json') |
| | | 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) |
| | | } |
| | | } |
New file |
| | |
| | | '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) |
| | | } |
| | | |
| | | exports.cssLoaders = function (options) { |
| | | options = options || {} |
| | | |
| | | const cssLoader = { |
| | | loader: 'css-loader', |
| | | options: { |
| | | sourceMap: options.sourceMap |
| | | } |
| | | } |
| | | |
| | | const postcssLoader = { |
| | | loader: 'postcss-loader', |
| | | options: { |
| | | sourceMap: options.sourceMap |
| | | } |
| | | } |
| | | |
| | | // generate loader string to be used with extract text plugin |
| | | 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, |
| | | publicPath: '../../', //加上这一条就好了 |
| | | 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') |
| | | } |
| | | } |
| | | |
| | | // Generate loaders for standalone style files (outside of .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') |
| | | }) |
| | | } |
| | | } |
New file |
| | |
| | | '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' |
| | | } |
| | | } |
New file |
| | |
| | | 'use strict' |
| | | const path = require('path') |
| | | const utils = require('./utils') |
| | | const config = require('../config') |
| | | const vueLoaderConfig = require('./vue-loader.conf') |
| | | const webpack = require('webpack') //这里引入webpack |
| | | |
| | | function resolve (dir) { |
| | | return path.join(__dirname, '..', dir) |
| | | } |
| | | |
| | | |
| | | |
| | | module.exports = { |
| | | context: path.resolve(__dirname, '../'), // 基础目录,绝对路径,用于从配置中解析入口起点(entry point)和 loader |
| | | 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: { // 模块别名列表 这也是 @指向src 的原因 |
| | | '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')] |
| | | }, |
| | | { |
| | | 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' |
| | | }, |
| | | plugins: [ |
| | | new webpack.ProvidePlugin({ |
| | | $: "jquery", |
| | | jQuery: "jquery", |
| | | jquery: "jquery", |
| | | "window.jQuery": "jquery" |
| | | }) |
| | | ], |
| | | } |
New file |
| | |
| | | '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') |
| | | |
| | | 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 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, |
| | | 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: '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 |
| | | |
| | | // 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) |
| | | } |
| | | }) |
| | | }) |
New file |
| | |
| | | 'use strict' |
| | | const path = require('path') |
| | | const utils = require('./utils') |
| | | const webpack = require('webpack') |
| | | const config = require('../config') |
| | | const merge = require('webpack-merge') |
| | | const baseWebpackConfig = require('./webpack.base.conf') |
| | | const CopyWebpackPlugin = require('copy-webpack-plugin') |
| | | const HtmlWebpackPlugin = require('html-webpack-plugin') |
| | | const ExtractTextPlugin = require('extract-text-webpack-plugin') |
| | | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') |
| | | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') |
| | | |
| | | const env = require('../config/prod.env') |
| | | |
| | | const webpackConfig = merge(baseWebpackConfig, { |
| | | module: { |
| | | rules: utils.styleLoaders({ |
| | | sourceMap: config.build.productionSourceMap, |
| | | extract: true, |
| | | usePostCSS: true |
| | | }) |
| | | }, |
| | | devtool: config.build.productionSourceMap ? config.build.devtool : false, |
| | | output: { |
| | | path: config.build.assetsRoot, |
| | | 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 |
| | | }), |
| | | new UglifyJsPlugin({ |
| | | uglifyOptions: { |
| | | compress: { |
| | | warnings: false |
| | | } |
| | | }, |
| | | sourceMap: config.build.productionSourceMap, |
| | | parallel: true |
| | | }), |
| | | // extract css into its own file |
| | | new ExtractTextPlugin({ |
| | | filename: utils.assetsPath('css/[name].[contenthash].css'), |
| | | // Setting the following option to `false` will not extract CSS from codesplit chunks. |
| | | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. |
| | | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, |
| | | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 |
| | | allChunks: true, |
| | | }), |
| | | // Compress extracted CSS. We are using this plugin so that possible |
| | | // duplicated CSS from different components can be deduped. |
| | | new OptimizeCSSPlugin({ |
| | | cssProcessorOptions: config.build.productionSourceMap |
| | | ? { safe: true, map: { inline: false } } |
| | | : { safe: true } |
| | | }), |
| | | // 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 |
| | | new HtmlWebpackPlugin({ |
| | | filename: config.build.index, |
| | | template: 'index.html', |
| | | favicon: path.resolve('favicon.ico'), // 引入图片地址 |
| | | 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' |
| | | }), |
| | | // keep module.id stable when vendor modules does not change |
| | | new webpack.HashedModuleIdsPlugin(), |
| | | // enable scope hoisting |
| | | new webpack.optimize.ModuleConcatenationPlugin(), |
| | | // split vendor js into its own file |
| | | new webpack.optimize.CommonsChunkPlugin({ |
| | | name: 'vendor', |
| | | minChunks (module) { |
| | | // any required modules inside node_modules are extracted to vendor |
| | | return ( |
| | | module.resource && |
| | | /\.js$/.test(module.resource) && |
| | | module.resource.indexOf( |
| | | path.join(__dirname, '../node_modules') |
| | | ) === 0 |
| | | ) |
| | | } |
| | | }), |
| | | // extract webpack runtime and module manifest to its own file in order to |
| | | // prevent vendor hash from being updated whenever app bundle is updated |
| | | new webpack.optimize.CommonsChunkPlugin({ |
| | | name: 'manifest', |
| | | minChunks: Infinity |
| | | }), |
| | | // This instance extracts shared chunks from code splitted chunks and bundles them |
| | | // in a separate chunk, similar to the vendor chunk |
| | | // 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 |
| | | }), |
| | | |
| | | // copy custom static assets |
| | | new CopyWebpackPlugin([ |
| | | { |
| | | from: path.resolve(__dirname, '../static'), |
| | | to: config.build.assetsSubDirectory, |
| | | ignore: ['.*'] |
| | | } |
| | | ]) |
| | | ] |
| | | }) |
| | | |
| | | if (config.build.productionGzip) { |
| | | const CompressionWebpackPlugin = require('compression-webpack-plugin') |
| | | |
| | | webpackConfig.plugins.push( |
| | | new CompressionWebpackPlugin({ |
| | | asset: '[path].gz[query]', |
| | | algorithm: 'gzip', |
| | | test: new RegExp( |
| | | '\\.(' + |
| | | config.build.productionGzipExtensions.join('|') + |
| | | ')$' |
| | | ), |
| | | threshold: 10240, |
| | | minRatio: 0.8 |
| | | }) |
| | | ) |
| | | } |
| | | |
| | | if (config.build.bundleAnalyzerReport) { |
| | | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin |
| | | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) |
| | | } |
| | | |
| | | module.exports = webpackConfig |