我在我的后端网站上使用dotnet核心,使用MVC网页(index.cshtml)和angular2作为我的应用程序。
我的问题是,对于每个新版本,用户都会获取旧的javascript文件,因为我的index.cshtml看起来像这样
@{
Layout = "";
}
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
</head>
<!-- 3. Display the application -->
<body>
<my-app>
<div class="container text-md-center">
<div class="mb-1">Loading application, please wait...</div>
<div>
<i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i>
<span class="sr-only">Loading...</span>
</div>
</div>
</my-app>
<script defer type="text/javascript" src="~/dist/webpack.bundle.js"></script>
@if (ViewBag.Environment != "Production")
{
<script defer type="text/javascript" src="~/dist/app-style.bundle.js"></script>
<script defer type="text/javascript" src="~/dist/vendor-style.bundle.js"></script>
}
<script defer type="text/javascript" src="~/dist/polyfills.bundle.js"></script>
<script defer type="text/javascript" src="~/dist/vendor.bundle.js"></script>
<script defer type="text/javascript" src="~/dist/builders.bundle.js"></script>
<script defer type="text/javascript" src="~/dist/app.bundle.js"></script>
</body>
</html>
我也在使用webpack捆绑所有的打字稿,html视图等。
在我的dotnet发布&#34; prepublish&#34;标签,我正在运行webpack来创建生产版本,如下所示
"scripts": {
"prepublish": [ "npm run build" ],
}
在我的package.json文件中,&#34; npm run build&#34;定义如此。
"scripts": {
"clean": "rimraf node_modules doc dist && npm cache clean",
"clean-install": "npm run clean && npm install",
"clean-start": "npm run clean-install && npm start",
"watch": "webpack --watch --progress --profile",
"debug": "rimraf dist && webpack --progress --profile --bail",
"build": "rimraf dist && webpack --progress --profile --bail",
"lint": "tslint --force \"wwwroot/app/**/*.ts\"",
"docs": "typedoc --options typedoc.json wwwroot/app/app.component.ts",
"postinstall": "npm run"
},
这一切都很好,但是因为dotnet发布将文件复制到新位置,并且webpack在复制之前运行...如何更新我的index.cshtml文件以包含脚本文件的哈希标记,而不更改实际的index.cshtml文件,因为显然已经签入并且不希望每次发布时都发布新版本(因为它应该更像是模板)
非常感谢任何帮助!
修改 这是我的实际webpack.config.js文件
var path = require('path');
var webpack = require('webpack');
var autoprefixer = require('autoprefixer');
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin;
/**
* Env
* Get npm lifecycle event to identify the environment
*/
var ENV = process.env.npm_lifecycle_event;
var isTestWatch = ENV === 'test-watch';
var isTest = ENV === 'test' || isTestWatch;
var isProd = ENV === 'build';
console.log(isProd ? 'Production build...' : 'Debug build...');
// Webpack Config
module.exports = function makeWebpackConfig() {
/**
* Config
* Reference: http://webpack.github.io/docs/configuration.html
* This is the object where all configuration gets set
*/
var config = {};
/**
* Devtool
* Reference: http://webpack.github.io/docs/configuration.html#devtool
* Type of sourcemap to use per build type
*/
if (isProd) {
config.devtool = 'source-map';
}
else if (isTest) {
config.devtool = 'inline-source-map';
}
else {
config.devtool = 'source-map';
}
/**
* Entry
* Reference: http://webpack.github.io/docs/configuration.html#entry
*/
config.entry = isTest ? {} : {
'polyfills': './wwwroot/polyfills.ts',
'vendor': './wwwroot/vendor.ts',
'builders': './wwwroot/builders.ts',
'app': './wwwroot/app.ts',
'vendor-style': './wwwroot/style/vendor-style.ts',
'app-style': './wwwroot/style/app-style.ts'
};
/**
* Output
* Reference: http://webpack.github.io/docs/configuration.html#output
*/
config.output = isTest ? {} : {
path: './wwwroot/dist',
publicPath: './dist/',
filename: '[name].bundle.js',
sourceMapFilename: '[name].bundle.js.map',
chunkFilename: '[id].chunk.js'
};
/**
* Resolve
* Reference: http://webpack.github.io/docs/configuration.html#resolve
*/
config.resolve = {
// only discover files that have those extensions
extensions: ['.ts', '.js']
};
var atlOptions = '';
if (isTest && !isTestWatch) {
// awesome-typescript-loader needs to output inlineSourceMap for code coverage to work with source maps.
atlOptions = 'inlineSourceMap=true&sourceMap=false';
}
/**
* Loaders
* Reference: http://webpack.github.io/docs/configuration.html#module-loaders
* List: http://webpack.github.io/docs/list-of-loaders.html
* This handles most of the magic responsible for converting modules
*/
config.module = {
rules: [
// .ts files for TypeScript
{
test: /\.ts$/,
loader: 'awesome-typescript-loader?' + atlOptions,
exclude: [isTest ? /\.(e2e)\.ts$/ : /\.(spec|e2e)\.ts$/, /node_modules\/(?!(ng2-.+))/]
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: ['css-loader', 'postcss-loader'] })
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: ['css-loader', 'postcss-loader', 'sass-loader'] })
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
hash: 'sha512',
digest: 'hex',
name: '[hash].[ext]'
}
},
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
optimizationLevel: 7,
interlaced: false
}
}
]
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader'
},
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
prefix: 'font/',
limit: 5000,
publicPath: '../dist/'
}
}
]
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
publicPath: '../dist/'
}
}
]
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml'
}
}
]
}
]
};
if (!isTest || !isTestWatch) {
// tslint support
config.module.rules.push({
test: /\.ts$/,
enforce: 'pre',
loader: 'tslint-loader'
});
}
/**
* Plugins
* Reference: http://webpack.github.io/docs/configuration.html#plugins
* List: http://webpack.github.io/docs/list-of-plugins.html
*/
config.plugins = [
// Define env variables to help with builds
// Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
new webpack.DefinePlugin({
// Environment helpers
'process.env': {
ENV: JSON.stringify(ENV)
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: true,
options: {
/**
* Apply the tslint loader as pre/postLoader
* Reference: https://github.com/wbuchwalter/tslint-loader
*/
tslint: {
emitErrors: false,
failOnHint: false
},
// htmlLoader
htmlLoader: {
minimize: true,
removeAttributeQuotes: false,
caseSensitive: true,
customAttrSurround: [ [/#/, /(?:)/], [/\*/, /(?:)/], [/\[?\(?/, /(?:)/] ],
customAttrAssign: [ /\)?\]?=/ ]
},
// postcss
postcss: [
autoprefixer({
browsers: ['last 2 version']
})
]
}
})
];
if (!isTest && !isTestWatch) {
config.plugins.push(
new ForkCheckerPlugin(),
// Generate common chunks if necessary
// Reference: https://webpack.github.io/docs/code-splitting.html
// Reference: https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
new CommonsChunkPlugin({
name: ['app', 'builders', 'vendor', 'polyfills', 'webpack'],
minChunks: Infinity
}),
// Extract css files
// Reference: https://github.com/webpack/extract-text-webpack-plugin
// Disabled when in test mode or not in build mode
new ExtractTextPlugin({
filename: '[name].css',
disable: !isProd
})
);
}
// Add build specific plugins
if (isProd) {
config.plugins.push(
// Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin
// Only emit files when there are no errors
new webpack.NoErrorsPlugin(),
// // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
// // Dedupe modules in the output
// new webpack.optimize.DedupePlugin(),
// Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
// Minify all javascript, switch loaders to minimizing mode
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
mangle: {
keep_fnames: true
}
})
);
}
return config;
}();
答案 0 :(得分:2)
以下是答案......其他人添加了一个很好的指南
https://scottaddie.com/2015/12/14/a-practical-approach-to-cache-busting-with-webpack-and-asp-net-5/
答案 1 :(得分:0)
警告:我自己没有使用这种方法。我尝试了,但多个匹配的文件问题很痛苦。留下答案,以防它可以帮助处于不同情况的人。
另一种方法是:
以下是一些示例代码,尽管有哈希名称,但仍可找到匹配的物理文件。我将把它集成到BundleConfig.cs作为读者练习,因为它可能会有所不同,具体取决于你还有什么。此外,它需要更改才能获得最新的文件。
private static string ReplaceHash(string pathWithHash)
{
var i = pathWithHash.LastIndexOf('/');
var virtualPath = pathWithHash.Substring(0, i);
var physicalPath = HostingEnvironment.MapPath(virtualPath);
var fileName = pathWithHash.Substring(i + 1);
if (!Directory.Exists(physicalPath))
{
throw new FfcException(string.Format("Bundle path '{0}' not found", pathWithHash));
}
var re = new Regex(fileName
.Replace(".", @"\.")
.Replace("{hash}", @"([0-9a-fA-F]+)")
.Replace("{version}", @"(\d+(?:\.\d+){1,3})")
.Replace("*", @".*")
, RegexOptions.IgnoreCase
);
fileName = fileName
.Replace("{hash}", "*")
.Replace("{version}", "*");
var matchingFiles = Directory.EnumerateFiles(physicalPath, fileName).Where(file => re.IsMatch(file)).ToList();
if (matchingFiles.Count == 0)
{
throw new FfcException(string.Format("Bundle resource '{0}' not found", pathWithHash));
}
if (matchingFiles.Count > 1)
{
// TODO: need to pick the most recently created matching file
throw new FfcException(string.Format("Ambiguous Bundle resource '{0}' requested", pathWithHash));
}
var matchingPhysicalFile = matchingFiles[0];
var matchingVirtualFile = matchingPhysicalFile.Replace(physicalPath + "\\", virtualPath + "/");
return matchingVirtualFile;
}
答案 2 :(得分:-1)
这可以在您的webpack配置
中配置 output: {
path: path.resolve(__dirname, './your-output-dir'),
publicPath: '/your-output-dir/',
filename: '[name][hash].js'
},
因此它将是
/dist/appasdadfasd.js //something like that
您将不会遇到缓存问题。
<script defer type="text/javascript" src="~/dist/app.bundle.js"></script>
您的app.bundle.js
将指向此文件/dist/appasdadfasd.js