staven630 / vue-cli4-config

vue-cli4配置vue.config.js持续更新

Home Page:https://staven630.github.io/vue-cli4-config/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TypeError: Cannot set property 'cdn' of undefined

3344567 opened this issue · comments

commented

image

// const SpritesmithPlugin = require("webpack-spritesmith");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const webpack = require("webpack");

const path = require("path");
const fs = require("fs");
const resolve = dir => path.join(__dirname, dir);
const IS_PROD = ["production", "prod"].includes(process.env.NODE_ENV);

const glob = require("glob");
const pagesInfo = require("./pages.config");
const pages = {};

glob.sync("./src/**/main.js").forEach(p => {
let result = p.match(/./src/(.*)/main.js/);
result = result ? result[1] : "";
const key = result ? result : "main";
if (pagesInfo[key]) {
pages[key] = {
entry: result ? src/${result}/main.js : "src/main.js"
};
for (const info in pagesInfo[key]) {
pages[key] = {
...pages[key],
[info]: pagesInfo[key][info]
};
}
}
});

let has_sprite = true;
let files = [];
const icons = {};

try {
fs.statSync(resolve("./src/assets/icons"));
files = fs.readdirSync(resolve("./src/assets/icons"));
files.forEach(item => {
let filename = item.toLocaleLowerCase().replace(/_/g, "-");
icons[filename] = true;
});
} catch (error) {
fs.mkdirSync(resolve("./src/assets/icons"));
}

if (!files.length) {
has_sprite = false;
} else {
try {
let iconsObj = fs.readFileSync(resolve("./icons.json"), "utf8");
iconsObj = JSON.parse(iconsObj);
has_sprite = files.some(item => {
let filename = item.toLocaleLowerCase().replace(/_/g, "-");
return !iconsObj[filename];
});
if (has_sprite) {
fs.writeFileSync(resolve("./icons.json"), JSON.stringify(icons, null, 2));
}
} catch (error) {
fs.writeFileSync(resolve("./icons.json"), JSON.stringify(icons, null, 2));
has_sprite = true;
}
}

// 雪碧图样式处理模板
const SpritesmithTemplate = function(data) {
// pc
let icons = {};
let tpl = .ico { display: inline-block; background-image: url(${data.sprites[0].image}); background-size: ${data.spritesheet.width}px ${data.spritesheet.height}px; };

data.sprites.forEach(sprite => {
	const name = "" + sprite.name.toLocaleLowerCase().replace(/_/g, "-");
	icons[`${name}.png`] = true;
	tpl = `${tpl} 

.ico-${name}{
width: ${sprite.width}px;
height: ${sprite.height}px;
background-position: ${sprite.offset_x}px ${sprite.offset_y}px;
}
`;
});
return tpl;
};

module.exports = {
publicPath: IS_PROD ? process.env.VUE_APP_PUBLIC_PATH : "./", // 默认'/',部署应用包时的基本 URL
// outputDir: process.env.outputDir || 'dist', // 'dist', 生产环境构建文件的目录
// assetsDir: "", // 相对于outputDir的静态资源(js、css、img、fonts)目录
configureWebpack: config => {
const plugins = [];

	if (has_sprite) {
		// 生成雪碧图
		// plugins.push(
		// 	new SpritesmithPlugin({
		// 		src: {
		// 			cwd: path.resolve(__dirname, "./src/assets/icons/"), // 图标根路径
		// 			glob: "**/*.png" // 匹配任意 png 图标
		// 		},
		// 		target: {
		// 			image: path.resolve(__dirname, "./src/assets/images/sprites.png"), // 生成雪碧图目标路径与名称
		// 			// 设置生成CSS背景及其定位的文件或方式
		// 			css: [
		// 				[
		// 					path.resolve(__dirname, "./src/assets/scss/sprites.scss"),
		// 					{
		// 						format: "function_based_template"
		// 					}
		// 				]
		// 			]
		// 		},
		// 		customTemplates: {
		// 			function_based_template: SpritesmithTemplate
		// 		},
		// 		apiOptions: {
		// 			cssImageRef: "../images/sprites.png" // css文件中引用雪碧图的相对位置路径配置
		// 		},
		// 		spritesmithOptions: {
		// 			padding: 2
		// 		}
		// 	})
		// );
	}

	config.externals = {
		vue: "Vue",
		"element-ui": "ELEMENT",
		"vue-router": "VueRouter",
		vuex: "Vuex",
		axios: "axios"
	};

	config.plugins = [...config.plugins, ...plugins];
},
chainWebpack: config => {
	// 修复HMR
	config.resolve.symlinks(true);

	config.plugin("ignore").use(new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn$/));

	// 添加别名
	config.resolve.alias
		.set("vue$", "vue/dist/vue.esm.js")
		.set("@", resolve("src"))
		.set("@apis", resolve("src/apis"))
		.set("@assets", resolve("src/assets"))
		.set("@scss", resolve("src/assets/scss"))
		.set("@components", resolve("src/components"))
		.set("@middlewares", resolve("src/middlewares"))
		.set("@mixins", resolve("src/mixins"))
		.set("@plugins", resolve("src/plugins"))
		.set("@router", resolve("src/router"))
		.set("@store", resolve("src/store"))
		.set("@utils", resolve("src/utils"))
		.set("@views", resolve("src/views"))
		.set("@layouts", resolve("src/layouts"));

	const cdn = {
		// 访问https://unpkg.com/element-ui/lib/theme-chalk/index.css获取最新版本
		css: ["//unpkg.com/element-ui@2.10.1/lib/theme-chalk/index.css"],
		js: [
			"//unpkg.com/vue@2.6.10/dist/vue.min.js", // 访问https://unpkg.com/vue/dist/vue.min.js获取最新版本
			"//unpkg.com/vue-router@3.0.6/dist/vue-router.min.js",
			"//unpkg.com/vuex@3.1.1/dist/vuex.min.js",
			"//unpkg.com/axios@0.19.0/dist/axios.min.js",
			"//unpkg.com/element-ui@2.10.1/lib/index.js"
		]
	};

	// 如果使用多页面打包,使用vue inspect --plugins查看html是否在结果数组中
	// config.plugin("html").tap(args => {
	//   // html中添加cdn
	//   args[0].cdn = cdn;

	//   // 修复 Lazy loading routes Error
	//   args[0].chunksSortMode = "none";
	//   return args;
	// });

	// 防止多页面打包卡顿
	config => config.plugins.delete("named-chunks");

	// 多页面cdn添加
	Object.keys(pagesInfo).forEach(page => {
		config.plugin(`html-${page}`).tap(args => {
			// html中添加cdn
			args[0].cdn = cdn;

			// 修复 Lazy loading routes Error
			args[0].chunksSortMode = "none";
			return args;
		});
	});

	if (IS_PROD) {
		// 压缩图片
		config.module
			.rule("images")
			.test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
			.use("image-webpack-loader")
			.loader("image-webpack-loader")
			.options({
				mozjpeg: { progressive: true, quality: 65 },
				optipng: { enabled: false },
				pngquant: { quality: [0.65, 0.9], speed: 4 },
				gifsicle: { interlaced: false }
			});

		// 打包分析
		config.plugin("webpack-report").use(BundleAnalyzerPlugin, [
			{
				analyzerMode: "static"
			}
		]);
	}

	// 使用svg组件
	const svgRule = config.module.rule("svg");
	svgRule.uses.clear();
	svgRule.exclude.add(/node_modules/);
	svgRule
		.test(/\.svg$/)
		.use("svg-sprite-loader")
		.loader("svg-sprite-loader")
		.options({
			symbolId: "icon-[name]"
		});

	const imagesRule = config.module.rule("images");
	imagesRule.exclude.add(resolve("src/icons"));
	config.module.rule("images").test(/\.(png|jpe?g|gif|svg)(\?.*)?$/);

	return config;
},
pages,
css: {
	extract: IS_PROD,
	sourceMap: false,
	loaderOptions: {
		scss: {
			// 向全局sass样式传入共享的全局变量, $src可以配置图片cdn前缀
			// 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
			prependData: `
      @import "@scss/variables.scss";
      @import "@scss/mixins.scss";
      @import "@scss/function.scss";
      $src: "${process.env.VUE_APP_BASE_API}";
      `
		}
	}
},
lintOnSave: false,
runtimeCompiler: true, // 是否使用包含运行时编译器的 Vue 构建版本
productionSourceMap: !IS_PROD, // 生产环境的 source map
parallel: require("os").cpus().length > 1,
pwa: {},
devServer: {
	// overlay: { // 让浏览器 overlay 同时显示警告和错误
	//   warnings: true,
	//   errors: true
	// },
	// open: false, // 是否打开浏览器
	// host: "localhost",
	// port: "8080", // 代理断就
	// https: false,
	// hotOnly: false, // 热更新
	proxy: {
		"/api": {
			target: "https://www.easy-mock.com/mock/5bc75b55dc36971c160cad1b/sheets", // 目标代理接口地址
			secure: false,
			changeOrigin: true, // 开启代理,在本地创建一个虚拟服务端
			// ws: true, // 是否启用websockets
			pathRewrite: {
				"^/api": "/"
			}
		}
	}
}

};

commented

代码部分就是你的完整配置,然后去除了雪碧图
image
问题似乎在pages上,
image

但我不知道应该如何引入才是对的

用了多页面pages,就会出现。仔细看“多页面打包 multi-page”这一节