最近越看項目越不順眼,流程和打包實在太老了,用node8以上的版本無法識别gulp,打包後的代碼也沒有壓縮,頁面也沒有source指引,html手動更換連結等等。。。
so,下決心把這塊兒更新一下
原本的node版本也太低,這次一起升,下載下傳node.js。。。
有興趣的可以在github下載下傳試試,一起交流。
因為用慣了之前的gulp流程化,加上項目的多入口多出口,這次決定還是繼續gulp+webpack。查了一下現在已經不是gulp-webpack了,而是webpack-stream,本次gulp隻作為任務流,主要還是webpack,配置來了
先看最終效果圖

檔案結構
多個項目整合在一起,要分開單獨打包,感覺還是用gulp來執行webpack更合适一點,個人了解而已。
package.json
以下就是所有的依賴了,這裡沒什麼好說的,要什麼就install什麼
下面的 browserslist 是為css自動添加字首用的
-2020.5.27 更新-
-2020.6.8 更新-
-2020.6.18 更新-
{
"name": "webpack-stream",
"version": "1.0.0",
"description": "",
"private": true,
"keywords": [],
"author": "JackSY",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.9.6",
"@babel/plugin-proposal-class-properties": "^7.4.4",
"@babel/plugin-proposal-decorators": "^7.4.4",
"@babel/plugin-transform-object-assign": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.4.4",
"@babel/preset-env": "^7.9.6",
"@babel/runtime": "^7.4.4",
"@babel/runtime-corejs2": "^7.4.4",
"babel-core": "^6.26.3",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"babel-plugin-dynamic-import-webpack": "^1.1.0",
"babel-plugin-lodash": "^3.3.4",
"clean-css": "^4.2.3",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.5.3",
"cssnano": "^4.1.10",
"eslint": "^7.1.0",
"eslint-config-standard": "^14.1.1",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-flowtype": "^5.1.3",
"eslint-plugin-html": "^6.0.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.2.2",
"file-loader": "^6.0.0",
"friendly-errors-webpack-plugin": "^1.7.0",
"gulp": "^4.0.2",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^4.3.0",
"image-webpack-loader": "^6.0.0",
"less-loader": "^6.1.0",
"lodash": "^4.17.15",
"lodash-webpack-plugin": "^0.11.5",
"mini-css-extract-plugin": "^0.9.0",
"node-notifier": "^7.0.1",
"node-sass": "^4.14.1",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"sass-loader": "^8.0.2",
"style-loader": "^1.2.1",
"uglify-js": "^3.9.3",
"url-loader": "^4.1.0",
"vue": "^2.6.11",
"vue-loader": "^15.9.2",
"vue-router": "^3.3.2",
"vue-server-renderer": "^2.6.11",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"vuex": "^3.4.0",
"webpack": "^4.43.0",
"webpack-dev-server": "^3.11.0",
"webpack-stream": "^5.2.1"
},
"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
]
}
webpack.dev.conf.js
開發模式已經添加了devServer,在gulp中動态添加,可以及時響應更改,而無需一遍又一遍地打包
-2020.5.27 更新-
-2020.6.8 更新-
-2020.6.18 更新-
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin");
const LodashWebpackPlugin = require("lodash-webpack-plugin");
const notifier = require("node-notifier");
const InsertHtmlPlugin = require("./public/insert-html-code-plugin");
const statistics = require("./public/statisticsTemplate");
module.exports = {
mode: "development",
output: {
filename: "build.js",
globalObject: "this"
},
stats: {
children: false // Tells stats whether to add information about the children.
},
plugins: [
new HtmlWebpackPlugin({
hash: true,
meta: false
}),
new VueLoaderPlugin(),
new MiniCssExtractPlugin(),
new LodashWebpackPlugin(),
new FriendlyErrorsPlugin({
// 運作錯誤
onErrors: function (severity, errors) {
// 可以收聽插件轉換和優先級的錯誤
// 嚴重性可以是"錯誤"或"警告"
if (severity !== "error") {
return;
}
const error = errors[0];
notifier.notify({
title: "Webpack error",
message: severity + ": " + error.name,
subtitle: error.file || ""
});
},
// 是否每次編譯之間清除控制台
// 預設為true
clearConsole: true
}),
new InsertHtmlPlugin({
minimize: false,
scriptCode: statistics,
scriptPaths: [
'https://cdn.bootcdn.net/ajax/libs/jquery/1.8.2/jquery.min.js'
]
}),
new webpack.HotModuleReplacementPlugin() // webpack内置的熱更新插件
],
externals: {
jquery: "jQuery"
},
resolve: {
extensions: [".vue", ".js", ".scss", ".sass", ".less", ".css", ".json"],
alias: {
vue$: "vue/dist/vue.esm.js"
}
},
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.css$/,
use: [
"vue-style-loader",
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true
}
},
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 1
}
},
{
loader: "postcss-loader",
options: {
plugins: (loader) => [
require("postcss-import")({
root: loader.resourcePath
}),
require("postcss-preset-env")(),
require("cssnano")()
],
sourceMap: true
}
}
]
},
{
test: /\.(sass|scss)$/,
use: [
"vue-style-loader",
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true
}
},
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 2
}
},
{
loader: "postcss-loader",
options: {
plugins: (loader) => [
require("postcss-import")({
root: loader.resourcePath
}),
require("postcss-preset-env")(),
require("cssnano")()
],
sourceMap: true
}
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
},
{
test: /\.less$/,
use: [
"vue-style-loader",
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true
}
},
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 2
}
},
{
loader: "postcss-loader",
options: {
plugins: (loader) => [
require("postcss-import")({
root: loader.resourcePath
}),
require("postcss-preset-env")(),
require("cssnano")()
],
sourceMap: true
}
},
{
loader: "less-loader",
options: {
sourceMap: true
}
}
]
},
{
test: /\.vue$/,
loader: "vue-loader"
},
{
test: /\.js$/,
use: [{
loader: "eslint-loader",
options: { // 這裡的配置項參數将會被傳遞到 eslint 的 CLIEngine
formatter: require("eslint-friendly-formatter") // 指定錯誤報告的格式規範
}
}],
enforce: "pre", // 編譯前檢查
exclude: [/node_modules/] // 不檢測的檔案
},
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: file => (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file)
)
},
{
test: /\.(png|jp?g|gif|svg|ico)$/,
use: [
{
loader: "url-loader",
options: {
limit: 8192, // 小于8192位元組的圖檔打包成base 64圖檔
name: "images/[name].[hash:8].[ext]",
publicPath: "./",
esModule: false
}
}
]
},
{
// 檔案依賴配置項——字型圖示
test: /\.(woff|woff2|svg|eot|ttf)$/,
use: [{
loader: "file-loader",
options: {
limit: 8192,
name: "fonts/[name].[hash:8].[ext]",
publicPath: "./"
}
}]
},
{
// 檔案依賴配置項——音頻
test: /\.(wav|mp3|ogg)?$/,
use: [{
loader: "file-loader",
options: {
limit: 8192,
name: "audios/[name].[hash:8].[ext]",
publicPath: "./"
}
}]
},
{
// 檔案依賴配置項——視訊
test: /\.(ogg|mpeg4|webm|mp4)?$/,
use: [{
loader: "file-loader",
options: {
limit: 8192,
name: "videos/[name].[hash:8].[ext]",
publicPath: "./"
}
}]
},
{
test: /\.(html)?$/,
use: {
loader: "html-loader",
options: {
minimize: false
}
}
}
]
}
}
gulpfile.js
-2020.5.27 更新-
-2020.6.8 更新-
-2020.6.18 更新-
為了拆分gulp任務,廢了我不少功夫
結構大概是這樣
index.js這樣
const activity2020 = require('./project');
const allGulpTasks = Object.assign({},
activity2020
);
Object.keys(allGulpTasks).forEach(key => {
exports[key] = allGulpTasks[key];
});
接下來是其他子任務project.js
const { src, dest } = require('gulp');
const webpackStream = require('webpack-stream');
const { webpackEntryOption, openWebpackDevServe } = require('../public/webpackOptionChange');
const gulpTasks = require('../gulpfile.json/project.json');
Object.keys(gulpTasks).forEach(key => {
const path = gulpTasks[key][0];
const outPath = gulpTasks[key][1] || 'dist';
const main = gulpTasks[key][2] || 'main';
const template = gulpTasks[key][3] || 'index.html';
exports['activity2020_' + key + '_dev'] = async function () {
openWebpackDevServe(path, outPath, main, template);
};
exports['activity2020_' + key + '_prod'] = function () {
return src('**/*.js', { allowEmpty: true })
.pipe(webpackStream(webpackEntryOption(path, outPath, true, main, template)))
.pipe(dest(path + outPath + '/'));
};
});
這裡在dev任務時gulp是異步任務,為的是開啟webpack的devServer
當然,一些方法我封裝了一下,比如 openWebpackDevServe 和 webpackEntryOption ,具體可以去我的github上交流一下
注意
有的電腦可能需要 powershell 開啟權限,管理者執行 set-executionpolicy RemoteSigned
這個配置裡:
- 本項目以 webpack 打包為主,gulp 隻提供任務流
- node.js ^v12.14.3
- gulp -g ^v4.0.0 (全局更新可能會失敗,用 --force 覆寫即可)
- gulp-cli -g ^v2.2.1
- 若 npm 安裝失敗請使用 cnpm 或 yarn
webpack.prod.conf.js
-2020.5.27 更新-
-2020.6.8 更新-
-2020.6.18 更新-
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const LodashWebpackPlugin = require("lodash-webpack-plugin");
const UglifyjsWebapckPlugin = require('uglifyjs-webpack-plugin');
const InsertHtmlPlugin = require("./public/insert-html-code-plugin");
const statistics = require("./public/statisticsTemplate");
module.exports = {
mode: "production",
output: {
filename: "js/[name].build.js",
globalObject: "this"
},
stats: {
children: false // Tells stats whether to add information about the children.
},
performance: {
maxEntrypointSize: 500000, // 入口檔案最大限制提示
maxAssetSize: 200000 // 輸出檔案最大限制提示
},
optimization: {
minimizer: [
new UglifyjsWebapckPlugin({
uglifyOptions: {
compress: {
// 設定打包時将console語句不打包進去
drop_console: true
}
}
})
],
splitChunks: {
cacheGroups: {
// 處理入口chunk,同步的
vendors: {
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
name: 'vendors'
},
// 處理異步chunk
'async-vendors': {
test: /[\\/]node_modules[\\/]/,
minChunks: 2,
chunks: 'async',
name: 'async-vendors'
},
// 處理css
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
},
// 為每個入口提取出webpack runtime子產品
runtimeChunk: { name: 'manifest' }
},
plugins: [
new HtmlWebpackPlugin({
minify: { // 壓縮HTML檔案
removeComments: true, // 移除HTML中的注釋
collapseWhitespace: true, // 删除空白符與換行符
minifyCSS: true, // 壓縮内聯css(使用clean-css進行的壓縮)
minifyJS: true, // 壓縮html裡的js(使用uglify-js進行的壓縮)
removeAttributeQuotes: true // 移除屬性的引号
},
hash: true,
meta: false
}),
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].css'
}),
new LodashWebpackPlugin(),
new InsertHtmlPlugin({
minimize: true,
scriptCode: statistics,
scriptPaths: [
'https://cdn.bootcdn.net/ajax/libs/jquery/1.8.2/jquery.min.js'
]
}),
new CleanWebpackPlugin()
],
externals: {
jquery: "jQuery"
},
resolve: {
extensions: [".vue", ".js", ".scss", ".sass", ".less", ".css", ".json"],
alias: {
vue$: "vue/dist/vue.min.js"
}
},
module: {
rules: [
{
test: /\.css$/,
use: [
"vue-style-loader",
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true
}
},
{
loader: "css-loader",
options: {
importLoaders: 1
}
},
{
loader: "postcss-loader",
options: {
plugins: (loader) => [
require("postcss-import")({
root: loader.resourcePath
}),
require("postcss-preset-env")(),
require("cssnano")()
]
}
}
]
},
{
test: /\.(sass|scss)$/,
use: [
"vue-style-loader",
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true
}
},
{
loader: "css-loader",
options: {
importLoaders: 2
}
},
{
loader: "postcss-loader",
options: {
plugins: (loader) => [
require("postcss-import")({
root: loader.resourcePath
}),
require("postcss-preset-env")(),
require("cssnano")()
]
}
},
"sass-loader"
]
},
{
test: /\.less$/,
use: [
"vue-style-loader",
"style-loader",
{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true
}
},
{
loader: "css-loader",
options: {
importLoaders: 2
}
},
{
loader: "postcss-loader",
options: {
plugins: (loader) => [
require("postcss-import")({
root: loader.resourcePath
}),
require("postcss-preset-env")(),
require("cssnano")()
]
}
},
"less-loader"
]
},
{
test: /\.vue$/,
loader: "vue-loader"
},
{
test: /\.(js|jsx)$/,
loader: "babel-loader",
exclude: file => (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file)
)
},
{
test: /\.(png|jp?g|gif|svg|ico)$/,
use: [
{
loader: "url-loader",
options: {
limit: 8192, // 小于8192位元組的圖檔打包成base 64圖檔
name: "images/[name].[hash:8].[ext]",
publicPath: "../",
esModule: false
}
},
{
loader: "image-webpack-loader"
}
]
},
{
// 檔案依賴配置項——字型圖示
test: /\.(woff|woff2|svg|eot|ttf)$/,
use: [{
loader: "file-loader",
options: {
limit: 8192,
name: "fonts/[name].[hash:8].[ext]",
publicPath: "./"
}
}]
},
{
// 檔案依賴配置項——音頻
test: /\.(wav|mp3|ogg)?$/,
use: [{
loader: "file-loader",
options: {
limit: 8192,
name: "audios/[name].[hash:8].[ext]",
publicPath: "./"
}
}]
},
{
// 檔案依賴配置項——視訊
test: /\.(ogg|mpeg4|webm|mp4)?$/,
use: [{
loader: "file-loader",
options: {
limit: 8192,
name: "videos/[name].[hash:8].[ext]",
publicPath: "./"
}
}]
},
{
test: /\.(html)?$/,
use: {
loader: "html-loader",
options: {
minimize: false
}
}
}
]
}
}
暫時就這些吧,後續還要完善不少,但是已經可以出貨啦~~