Проект должен быть сделан как страница обмена нового приложения, поэтому необходимо сделать многостраничное приложение.Поскольку приложение новое, нам также нужно обновить его здесь.После многих расследований (Du Niang) мы интегрировали некоторые преимущества других людей и в сочетании с Project Live создали эту статью.
В этой статье опущены некоторые основные операции.
Отправить адрес github ---звезда, звезда, звезда меня
Каталог проекта:
1. webpack.base.conf.js
общедоступный файл конфигурации
const path = require('path');
const webpack = require("webpack");
const glob = require("glob");
require("./env-config");
// 分离css
//消除冗余的css
const purifyCssWebpack = require("purifycss-webpack");
// html模板
const htmlWebpackPlugin = require("html-webpack-plugin");
//静态资源输出
const copyWebpackPlugin = require("copy-webpack-plugin");
const rules = require("./webpack.rules.conf.js");
// 获取html-webpack-plugin参数的方法
var getHtmlConfig = function (name, chunks) {
return {
template: `./src/pages/${name}/index.html`,
filename: `${name}.html`,
// favicon: './favicon.ico',
// title: title,
inject: true,
hash: true, //开启hash ?[hash]
chunks: chunks,
minify: process.env.NODE_ENV === "development" ? false : {
removeComments: true, //移除HTML中的注释
collapseWhitespace: true, //折叠空白区域 也就是压缩代码
removeAttributeQuotes: true, //去除属性引用
},
};
};
function getEntry() {
var entry = {};
//读取src目录所有page入口
glob.sync('./src/pages/**/*.js')
.forEach(function (name) {
var start = name.indexOf('src/') + 4,
end = name.length - 3;
var eArr = [];
var n = name.slice(start, end);
n = n.slice(0, n.lastIndexOf('/')); //保存各个组件的入口
n = n.split('/')[1];
eArr.push(name);
entry[n] = eArr;
});
return entry;
};
module.exports = {
entry: getEntry(),
module: {
rules: [...rules]
},
resolve: {
alias: {
'@': path.resolve(__dirname, '../src')
}
},// 提取公共代码
optimization: {
splitChunks: {
cacheGroups: {
vendor: { // 抽离第三方插件
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'vendor', // 打包后的文件名,任意命名
// 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
priority: 10
}
}
}
},
plugins: [//静态资源输出
new copyWebpackPlugin([{
from: path.resolve(__dirname, "../src/assets"),
to: './assets',
ignore: ['.*']
}]),
// 消除冗余的css代码
new purifyCssWebpack({
paths: glob.sync(path.join(__dirname, "../src/pages/*/*.html"))
}),
]
}
//配置页面
const entryObj = getEntry();
const htmlArray = [];
Object.keys(entryObj).forEach(element => {
htmlArray.push({
_html: element,
title: '',
chunks: ['vendor', element]
})
})
//自动生成html模板
htmlArray.forEach((element) => {
module.exports.plugins.push(new htmlWebpackPlugin(getHtmlConfig(element._html, element.chunks)));
})
Хоть и есть комментарии, но все же поясню, не слишком ли это тактично... ^_^
const path = require('path');
const webpack = require("webpack");
const glob = require("glob");
require("./env-config"); //暂时先不管它,后面会讲
// 分离css
//消除冗余的css
const purifyCssWebpack = require("purifycss-webpack");
// html模板
const htmlWebpackPlugin = require("html-webpack-plugin");
//静态资源输出
const copyWebpackPlugin = require("copy-webpack-plugin");
const rules = require("./webpack.rules.conf.js");
По сути, это ссылка на некоторые переменные, кратко объясните glob и правила, glob - это то, что нам нужен этот плагин для обработки наших многостраничных путей, чтобы мы могли генерировать соответствующие несколько файлов после упаковки, а правила - это некоторые загрузчики Конфигурация, которую вы могу просто процитировать его напрямую, поэтому я не буду говорить об этом здесь.
// 获取html-webpack-plugin参数的方法
var getHtmlConfig = function (name, chunks) {
return {
template: `./src/pages/${name}/index.html`,
filename: `${name}.html`,
// favicon: './favicon.ico',
// title: title,
inject: true,
hash: true, //开启hash ?[hash]
chunks: chunks,
minify: process.env.NODE_ENV === "development" ? false : {
removeComments: true, //移除HTML中的注释
collapseWhitespace: true, //折叠空白区域 也就是压缩代码
removeAttributeQuotes: true, //去除属性引用
},
};
};
function getEntry() {
var entry = {};
//读取src目录所有page入口
glob.sync('./src/pages/**/*.js')
.forEach(function (name) {
var start = name.indexOf('src/') + 4,
end = name.length - 3;
var eArr = [];
var n = name.slice(start, end);
n = n.slice(0, n.lastIndexOf('/')); //保存各个组件的入口
n = n.split('/')[1];
eArr.push(name);
entry[n] = eArr;
});
return entry;
};
Эти два способа более важны, потому что, когда мы используем многостраничную упаковку, запись в module.exports (содержимое, описанное здесь, находится в этом файле, то же самое ниже) вообще нужно настроить таким образом
module.exports = {
entry: {
index: './src/pages/index/index.js' ,
page1: './src/pages/index/page1.js' ,
page2: './src/pages/index/page2.js'
}
//下面暂时忽略
/*...*/
}
В этом случае каждый раз, когда мы добавляем файл, нам нужно добавить один элемент.Хорошо, что страниц меньше.Когда страниц больше, очень сложно поддерживать или развивать, и мы вообще не рекомендуем изменять файл. конфигурационный файл.
Чтобы избежать таких операций, нам нужно определить эти два метода, которые помогут нам
Давайте сначала поговорим о getEntry, он фактически получает index.js каждой страницы под нашими страницами, а затем возвращает объект, поэтому нам не нужно добавлять его вручную.
И getHtmlConfig используется для взаимодействия с htmlwebpackplugin, htmlwebpackplugin нуждается в некоторой настройке, и наше многостраничное приложение должно создавать несколько html-файлов с одинаковой конфигурацией, но с разными именами, этот метод заключается в использовании параметров, которые мы передаем, для создания различных конфигураций имен страниц. .
Как мы все знаем, в одностраничном приложении нам нужен только один index.html, но в многостраничном нам нужны соответствующие страницы один к одному, и переход один за другим нового htmlwebpackplugin также нарушает наше первоначальное намерение.
//配置页面
const entryObj = getEntry();
const htmlArray = [];
Object.keys(entryObj).forEach(element => {
htmlArray.push({
_html: element,
title: '',
chunks: ['vendor', element]
})
})
//自动生成html模板
htmlArray.forEach((element) => {
module.exports.plugins.push(new htmlWebpackPlugin(getHtmlConfig(element._html, element.chunks)));
})
Наша страница обычная, то есть index.js соответствует соответствующему index.html, тогда мы можем использовать предыдущий getEntry для получения js-файла, сгенерировать соответствующий массив, использовать gethtmlconfig и положить его в htmlwebpackplugin.
2. webpack.dev.conf.js
Конфигурационный файл среды разработки:
const path = require('path');
const webpack = require("webpack");
const merge = require("webpack-merge");
const webpackConfigBase = require('./webpack.base.conf');
const webpackConfigDev = {
mode: 'development', // 通过 mode 声明开发环境
output: {
path: path.resolve(__dirname, '../dist'),
// 打包多出口文件
filename: './js/[name].bundle.js'
},
devServer: {
contentBase: path.join(__dirname, "../src"),
publicPath:'/',
host: "127.0.0.1",
port: "8090",
overlay: true, // 浏览器页面上显示错误
// open: true, // 开启浏览器
// stats: "errors-only", //stats: "errors-only"表示只打印错误:
hot: true, // 开启热更新
//服务器代理配置项
proxy: {
'/test/*':{
target: 'https://www.baidu.com',
secure: true,
changeOrigin: true
}
}
},
plugins: [
//热更新
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env.BASE_URL': '\"' + process.env.BASE_URL + '\"'
})
],
devtool: "source-map", // 开启调试模式
}
module.exports = merge(webpackConfigBase, webpackConfigDev);
требуется импорт
webpack-merge, чтобы объединить наши webpack.base.conf.js и webpack.dev.conf.js
прокси, потому что, если мы запустим среду разработки, она будет отлаживаться локально, и будут междоменные проблемы.Прокси действует как слой прокси для нас, чтобы решать междоменные проблемы.
webpack.DefinePlugin, мы поговорим об этом позже
требуется импорт
webpack-merge, чтобы объединить наши webpack.base.conf.js и webpack.dev.conf.js
прокси, потому что, если мы запустим среду разработки, она будет отлаживаться локально, и будут междоменные проблемы.Прокси действует как слой прокси для нас, чтобы решать междоменные проблемы.
webpack.DefinePlugin, мы поговорим об этом позже
3. webpack.prod.conf.js
Файл конфигурации рабочей среды:
const path = require('path');
const webpack = require("webpack");
const merge = require("webpack-merge");
// 清除目录等
const cleanWebpackPlugin = require("clean-webpack-plugin");
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const extractTextPlugin = require("extract-text-webpack-plugin");
const webpackConfigBase = require('./webpack.base.conf');
process.env.NODE_ENV = "test"
const webpackConfigProd = {
mode: 'production', // 通过 mode 声明生产环境
output: {
path: path.resolve(__dirname, '../dist'),
// 打包多出口文件
filename: './js/[name].[hash].js',
publicPath: './'
},
devtool: 'cheap-module-eval-source-map',
plugins: [
//删除dist目录
new cleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../'), //根目录
// verbose Write logs to console.
verbose: true, //开启在控制台输出信息
// dry Use boolean "true" to test/emulate delete. (will not remove files).
// Default: false - remove files
dry: false,
}),
new webpack.DefinePlugin({
'process.env.BASE_URL': '\"' + process.env.BASE_URL + '\"'
}),
// 分离css插件参数为提取出去的路径
new extractTextPlugin({
filename: 'css/[name].[hash:8].min.css',
}),
//压缩css
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
//上线压缩 去除console等信息webpack4.x之后去除了webpack.optimize.UglifyJsPlugin
new UglifyJSPlugin({
uglifyOptions: {
compress: {
warnings: false,
drop_debugger: false,
drop_console: true
}
}
})
],
module: {
rules: []
},
}
module.exports = merge(webpackConfigBase, webpackConfigProd);
требуется импорт cleanWebpackPlugin, мы будем создавать много файлов с разными именами (хэш разный) после каждой сборки, но нам не нужны предыдущие файлы, используйте этот плагин для очистки наших предыдущих файлов dist
Ну, эти два файла относительно просты, поэтому я не буду объяснять больше...
4. env-config.js
В обычных обстоятельствах мы можем использовать его, когда настраиваем его до этого момента, но из-за требований проекта нам необходимо настроить более 2 переменных среды (по умолчанию для веб-пакета используются две для разработки и производства)
И для наших разных сред могут потребоваться разные интерфейсы:
ps: текст ---> запрос test-api,
dev ---> запросить dev-api,
pro ---> запрос API,
...
На данный момент нам нужно использовать webpack.DefinePlugin, который не упоминался ранее.Этот плагин используется для объявления глобальных переменных.Мы определяем разные имена интерфейса в соответствии с разными командами упаковки.
'use strict'
const path = require('path')
/*
* 环境列表,第一个环境为默认环境
* envName: 指明现在使用的环境
* dirName: 打包的路径,只在build的时候有用
* baseUrl: 这个环境下面的api 请求的域名
* assetsPublicPath: 静态资源存放的域名,未指定则使用相对路径
* */
const ENV_LIST = [
{
//开发环境
envName: 'dev',
dirName: 'dev',
baseUrl: 'http://100.xxx.xxx',
assetsPublicPath:'/'
},
{
//测试环境
envName: 'test',
dirName: path.resolve(__dirname, '../dist'),
baseUrl: 'http://111.xxx.xxx',
assetsPublicPath: '/'
},
{
//生产环境(命令行参数(process.arg)中prod是保留字,所以使用pro)
envName: 'pro',
dirName: path.resolve(__dirname, '../dist'),
baseUrl: 'http://122.xxx.xxx',
assetsPublicPath:'/'
},
]
const argv = JSON.parse(process.env.npm_config_argv).original || process.argv
const HOST_ENV = argv[2] ? argv[2].replace(/[^a-z]+/ig,"") : ''
//没有设置环境,则默认为第一个
const HOST_CONF = HOST_ENV ? ENV_LIST.find(item => item.envName === HOST_ENV) : ENV_LIST[0]
// 把环境常量挂载到process.env方便客户端使用
process.env.BASE_URL = HOST_CONF.baseUrl
// process.env.ENV_NAME = HOST_CONF.envName
module.exports.HOST_CONF = HOST_CONF
module.exports.ENV_LIST = ENV_LIST
Мы объявляем массив, который используется для хранения наших переменных среды, и монтируем полученные переменные среды в process.env, Как я уже писал, мы напрямую console.log(process.env.BASE_URL) на стороне клиента Это текущая среда.
Так как же программа узнает, в какой среде мы упаковываем? Затем перейдите в package.json, чтобы сделать статью
"scripts": {
"test": "npm run build --[test]",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.conf.js",
"build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.conf.js"
}
Здесь я занимаюсь только настройкой тестовой среды, а остальным нужно только настроить npm run build --[xxx].Вот напоминание, dev и build лично считаю, что их не следует рассматривать как две переменные среды, а следует быть вашим методом упаковки (простите меня, я могу объяснить это только так), вы можете понять, что это среда отладки, а другая - онлайн-среда.
Чего я раньше не говорил, так это того, что webpack.base.config.js вводит наши переменные, а dev и prod объявляют нужные нам переменные глобально.
хорошо, вы можете в основном написать свою страницу здесь.
Все кончено, все кончено, все кончено...