Ne znam da se tu nešto naročito može primjetiti što nema gore u dokumentaciji…ali evo mog setupa:
webpack.common.js
const webpack = require("webpack");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
var WebpackNotifierPlugin = require('webpack-notifier');
module.exports = {
target: "web",
module: {
rules: [
// All files with a ".ts" or ".tsx" extension will be handled by "awesome-typescript-loader".
{ test: /\.ts$/, loader: "awesome-typescript-loader" },
{ test: /\.js$/, loader: 'bozoou_js2loader' },
// All image files will be handled here
{
test: /\.(png|svg|jpg|gif)$/,
use: [
"file-loader"
]
},
// All font files will be handled here
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: "file-loader"
}
]
},
// All files with ".html" will be handled
{ test: /\.html$/, loader: "html-loader" },
// All output ".js" files will have any sourcemaps re-processed by "source-map-loader".
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
plugins: ([
new WebpackNotifierPlugin({alwaysNotify:true}),
// make sure we allow any jquery usages outside of our webpack modules
// uz ovo dodaj u top entry point filea: $ = window.$;
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
}),
// Clean dist folder.
new CleanWebpackPlugin(["./dist"], {
"verbose": true // Write logs to console.
}),
// avoid publishing when compilation failed.
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({
inject: "body",
filename: "../views/layout.html",
template: "./views/layout_Template.php",
showErrors:true
})
]),
// pretty terminal output
stats: { colors: true }
};
webpack.dev.js
const path = require("path");
const webpack = require("webpack");
const Merge = require("webpack-merge");
const CommonConfig = require("./webpack.common.js");
module.exports = Merge(CommonConfig, {
devtool: "cheap-eval-source-map",
entry: path.resolve(__dirname, "js/index.js"),
output: {
filename: "output.[hash].bundle.js",
path: __dirname + "/dist",
// Making sure the CSS and JS files that are split out do not break the template cshtml.
publicPath: "./dist/",
// Defining a global var that can used to call functions from within ASP.NET Razor pages.
library: "aspAndWebpack",
libraryTarget: "var"
},
resolve: {
// Add ".ts" and ".tsx" as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json", ".html"],
alias: {
ROOT: path.resolve(__dirname, "./js/"),
CROSS: 'D:/Programiranje/RESOURCE/NPM-CROSS/node_modules', //individual per project
NODE_CONFIG: path.resolve(__dirname, "./node_config/"),
}
},
module: {
rules: [
// All css files will be handled here
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
// All files with ".less" will be handled and transpiled to css
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"]
},
// All files with ".scss" will be handled and transpiled to css
{
test: /\.scss/,
use: ["style-loader", "css-loader", "sass-loader"]
}
]
},
plugins: ([
new webpack.DefinePlugin({
"process.env": {
"NODE_ENV": JSON.stringify("development")
}
})
]),
})
webpack.prod.js
const path = require("path");
const webpack = require("webpack");
const Merge = require("webpack-merge");
const CommonConfig = require("./webpack.common.js");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const extractLess = new ExtractTextPlugin({
filename: "[name].[contenthash].css"
});
module.exports = Merge(CommonConfig, {
devtool: "hidden-source-map",
entry: {
index: path.resolve(__dirname, 'js/index.js'),
vendor: [
"jquery",
"jquery-validation",
"bootstrap",
"jquery-validation-unobtrusive"
]
},
output: {
filename: "[name].[chunkhash].js",
path: __dirname + "/dist",
// Making sure the CSS and JS files that are split out do not break the template cshtml.
publicPath: "./dist/",
// Defining a global var that can used to call functions from within ASP.NET Razor pages.
library: "aspAndWebpack",
libraryTarget: "var"
},
resolve: {
// Add ".ts" and ".tsx" as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json", ".html"],
alias: {
ROOT: path.resolve(__dirname, "./js/"),
CROSS: 'D:/Programiranje/RESOURCE/NPM-CROSS/node_modules', //individual per project
NODE_CONFIG: path.resolve(__dirname, "./node_config/"),
}
},
module: {
rules: [
// All css files will be handled here
{
test: /\.css$/,
use: extractLess.extract({ fallback: "style-loader", use: ["css-loader"] })
},
// All files with ".less" will be handled and transpiled to css
{
test: /\.less$/,
use: extractLess.extract({
use: [{
loader: "css-loader", options: {
sourceMap: true
}
}, {
loader: "less-loader", options: {
sourceMap: true
}
}]
})
},
// All files with ".scss" will be handled and transpiled to css
{
test: /\.scss/,
use: ["style-loader", "css-loader", "sass-loader"]
}
]
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
"NODE_ENV": JSON.stringify("production")
}
}),
// Split out library into seperate bundle and remove from app bundle.
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: "vendor"
}),
// Webpack boilerplate and manifest in seperate file.
new webpack.optimize.CommonsChunkPlugin({
name: "runtime"
}),
// Write out CSS bundle to its own file:
extractLess,
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
beautify: false,
mangle: {
screw_ie8: true,
keep_fnames: true
},
compress: {
screw_ie8: true,
toplevel:true
},
comments: false
})
]
})
Dev i Prod djele neke zajedničke segmente…moglo se više toga povezati preko common konfiguracije…ali nije strašno.
Od onog što se može primjetiti da sam tu dodao na “svoju ruku” je npr. bozoou_js2loader , to je moj prekompajler javascripta, (zasad) ne radi nešto naročito…ali par meni korisnih sitnica. Webpack mi je recimo zanimljiv upravo po tome što se jednostavno mogu ugraditi customizirani loaderi za određene tipove file-ova.
Nadalje, nešto što nisam u startu znao elegantno rješiti…to su sada ovi aliasovi. Tako imam alias za CROSS i NODE_CONFIG i to su mi čisto fine rješenja za sljedeće…
Dosta NPM komponenti si sam pravim i onda mi se pokazalo 101% nepraktičnim neku komponentu razvijati u njenoj source okolini…pa je od tamo uploadti u NPM repository…pa iz tog repozitorija instalirati updejtove u projekt. Znači ako trebaš neku sitnicu promjeniti na nekoj komponenti…to je ubij Bože vremena napraviti taj krug. A opet razvijat komponentu lokalno unutar projekta…je teški kaos za sve držati sinkroniziranim, pošto se iste komponente koriste uvijek na više projekata.
Tako sam si složio CROSS folder gdje mi čuče takve komponente koje reuse-am između projekata i onda ih tamo razvijam…a svi projekti se lokalno spajaju na taj CROSS folder. Naravno, ako kod importa komponente se to zada na način:
import {...} from "CROSS/component_name"
…onda je komponenta povučena iz CROSS foldera. A u konfiguraciji webpacka se mogu onda igrati koji je pravi source komponenti, tj. na koji folder će targetirati taj CROSS alias.
Time je razvoj drastično ubrzan…ali treba imati na umu da taj razvoj uvijek mora biti backward kompatibilan, pošto će svaka promjena utjecati na sve projekte koji se spajaju na CROSS. (Zato su tu automatski testovi Bogom dani, koji mogu samostalno zaključiti ako je došlo do promjene koja više nije backward kompatibilna)
Nadalje, NODE_CONFIG mi je alias za folder gdje se se nalazi customizacijski dio svake komponente, gdje je ta customizacija individualna po projektu.
Tako svaka komponenta koja ima konfiguracijski dio unutar sebe poziva:
import {...} from "NODE_CONFIG/someCustomizationFile"
…a onaj tko koristi takvu komponentu, mora u webpacku osigurati da postoji alias NODE_CONFIG i mora kustomizacijski file te komponente kopirati u folder koji je targetiran sa aliasom NODE_CONFIG.
Ovo sve sa dead code removingom, neće značajno promjeniti izgled webpack konfiguracije, sem ću se morati malo poigrati sa postavkama UglifyJsPlugin plugina. A dalje ću u codeu imati flagove za konstante poput:
const Develop = true;
…te ću prije bildanja postaviti te flagove kako mi odgovaraju za bildanje…i pokrenuti bildanje. Dalje će već dead code remover sve buildati kako treba s obzirom kako su ti flagovi postavljeni.
Ono što bi bilo malo bolje (ali ne znam kako se slaže, ako se može), da se ti flagovi mogu držati unutar webpack konfiguracije. Tako da kada trigiram recimo bildanje produkcijske verzije:
npm run build:prod
…da automatski pokretanjem te radnje se promjeni stanje flagova. Na taj način bi mogao jednoznačno odrediti koja vrsta bildanja ima koje stanje flagova. I samo bildanje bi bilo mrvicu praktičnije za odraditi. (Ono, ne moraš kopati po codeu prije bildanja i mijenjati stanje varijablama…tj. konstantama, hehe. Nego samo u cmd kucaš naredbu za buildanje i sve se desi samo po sebi. Time se ne mora ništa pamtiti…ili ti raditi u više koraka. Smatram da jedna procedura uvijek treba biti jedna procedura. Time smo smanjili teret koji nosimo dalje sa sobom i smanjujemo podložnost pogreški. Čim se jedna procedura mora napraviti u više koraka …moglo je bolje. )
P.S.
ovo nije neki ogledni primjer webpack konfiguracije.
Ja sam to poprilično na eks posložio prema uputama iz dokumentacije, bilo mi je samo bitno da radi, jer sam imao veliki time limit. …a ima tu svašta nešto čime se to može unaprijediti.
Nisam recimo uopće zašao u chunk-ove …a o njima treba razmisliti da se to poveže da svaki page učitava svoj bundle file. Nisam to još radio, mada smatram to praktički esencijalnim.
Jer ovako imamo jedan bundle file za cijeli projekt bez obzira što pageA i pageB trebaju možda sasvim druge skripte za izvršavanje svoje funkcionalnosti.
Za projekt koji ima par podstranica, to nije problem …ali ako ćemo o skalabilnosti i većem broju podstranica, onda treba razmisliti o tome da svaka stranica učitava samo ono što je njoj potrebno. To @belmin garant zna kako se radi.
Nadalje, treba proučiti kako sa webpackom asinkrono dohvaćat bundlove/module …pa se određene komponente mogu pozivati u igru tek kada zatrebaju…