我已将应用程序拆分为应用程序模块和 dll 模块,用于供应商(node_modules
)依赖项。 这是一个asp.net核心应用程序,其顶部有angular2
该应用似乎加载了大多数供应商模块(假设我实际上已将它们添加到供应商dll中),但我遇到了font-awesome
和bootstrap-colorpicker
的一些问题。当我使用DllReferencePlugin
时,他们的资产(图像和字体)无法解析。如果我在客户端应用程序中包含node_modules
的加载器用于字体和图像,我只能使用它。
但是,这意味着font-awesome
和bootstrap-colorpicker
现在是我的应用程序包的一部分......
我希望能够将它们保存在供应商包/ dll中。在下面的代码中,我注释了前面提到的node_modules
在客户端包中的包含:
/*
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?.*$|$)/,
include: [
helpers.root('node_modules','font-awesome'),
helpers.root('node_modules','bootstrap')
],
loader: 'file?name=vendor-missing/[name].[hash].[ext]'
},*/
但现在我在webpack构建期间收到错误:
...
[12] ./~/css-loader!./~/resolve-url-loader!./~/sass-loader?sourceMap!./app/scss/application.scss 371 kB {0} [built] [5 errors]
[13] ./~/css-loader/lib/css-base.js 1.46 kB {0} [built]
[14] ./~/css-loader!./~/nouislider/distribute/nouislider.min.css 3.65 kB {0} [built]
[15] ./~/css-loader!./~/bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css 4.27 kB {0} [built] [5 errors]
[16] ./~/bootstrap-colorpicker/dist/img/bootstrap-colorpicker/saturation.png 0 bytes [built] [failed]
[17] ./~/bootstrap-colorpicker/dist/img/bootstrap-colorpicker/hue.png 0 bytes [built] [failed]
[18] ./~/bootstrap-colorpicker/dist/img/bootstrap-colorpicker/alpha.png 0 bytes [built] [failed]
[19] ./~/bootstrap-colorpicker/dist/img/bootstrap-colorpicker/hue-horizontal.png 0 bytes [built] [failed]
[20] ./~/bootstrap-colorpicker/dist/img/bootstrap-colorpicker/alpha-horizontal.png 0 bytes [built] [failed]
[21] ./~/css-loader!./~/ng2-dnd/bundles/style.css 594 bytes {0} [built]
[22] ./~/font-awesome/fonts/fontawesome-webfont.eot 0 bytes [built] [failed]
[23] ./~/font-awesome/fonts/fontawesome-webfont.woff2 0 bytes [built] [failed]
[24] ./~/font-awesome/fonts/fontawesome-webfont.woff 0 bytes [built] [failed]
[25] ./~/font-awesome/fonts/fontawesome-webfont.ttf 0 bytes [built] [failed]
[26] ./~/font-awesome/fonts/fontawesome-webfont.svg 0 bytes [built] [failed]
...
+ 40 hidden modules
ERROR in ./~/font-awesome/fonts/fontawesome-webfont.eot
Module parse failed: C:\path\to\my\app\node_modules\font-awesome\fonts\fontawesome-webfont.eot Unexpected character '�' (1:1)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected character '�' (1:1)
at Parser.pp$4.raise (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:2221:15)
at Parser.pp$7.getTokenFromCode (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:2756:10)
at Parser.pp$7.readToken (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:2477:17)
at Parser.pp$7.nextToken (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:2468:15)
at Parser.pp$7.next (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:2413:10)
at Parser.pp$3.parseIdent (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:2191:10)
at Parser.pp$3.parseExprAtom (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1774:21)
at Parser.pp$3.parseExprSubscripts (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1715:21)
at Parser.pp$3.parseMaybeUnary (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1692:19)
at Parser.pp$3.parseExprOps (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1637:21)
at Parser.pp$3.parseMaybeConditional (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1620:21)
at Parser.pp$3.parseMaybeAssign (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1597:21)
at Parser.pp$3.parseExpression (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:1573:21)
at Parser.pp$1.parseStatement (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:727:47)
at Parser.pp$1.parseTopLevel (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:638:25)
at Parser.parse (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:516:17)
at Object.parse (C:\path\to\my\app\node_modules\acorn\dist\acorn.js:3098:39)
at Parser.parse (C:\path\to\my\app\node_modules\webpack\lib\Parser.js:902:15)
at DependenciesBlock.<anonymous> (C:\path\to\my\app\node_modules\webpack\lib\NormalModule.js:104:16)
at DependenciesBlock.onModuleBuild (C:\path\to\my\app\node_modules\webpack-core\lib\NormalModuleMixin.js:310:10)
at nextLoader (C:\path\to\my\app\node_modules\webpack-core\lib\NormalModuleMixin.js:275:25)
at C:\path\to\my\app\node_modules\webpack-core\lib\NormalModuleMixin.js:259:5
at Storage.finished (C:\path\to\my\app\node_modules\webpack\node_modules\enhanced-resolve\lib\CachedInputFileSystem.js:38:16)
at C:\path\to\my\app\node_modules\graceful-fs\graceful-fs.js:78:16
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:445:3)
@ ./~/css-loader!./~/resolve-url-loader!./~/sass-loader?sourceMap!./app/scss/application.scss 8:127867-127941 8:127964-128038
...
/app/scss/application.scss
@import "variables";
@import "mixins";
@import "~bootstrap/scss/bootstrap";
@import "~font-awesome/scss/font-awesome";
@import "glyphicons-halflings"; // is no longer a separate node_module because that package is broken af (defining non-existent urls)
@import "~pace/themes/pace-theme-flash";
@import "~animate.css/animate";
@import "~awesome-bootstrap-checkbox/awesome-bootstrap-checkbox";
@import "~nouislider/distribute/nouislider.min.css";
@import "~bootstrap-select/dist/css/bootstrap-select";
@import "~bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css";
@import "~ng2-dnd/bundles/style.css";
@import "custom-utils.scss";
// css overrides
@import "noUiSlider/_noUiSlider-overide.scss";
@import "nvd3/_nvd3-override.scss";
@import "angular2-grid/angular2-grid-override.scss";
@import "angular2-modal/_angular2-modal-override.scss";
@import "bootstrap-override";
@import "libs-override";
//
//end custom libs
//everything below this line is required for essential styling
@import "font";
@import "general";
@import "global-transitions";
@import "base";
@import "utils";
@import "print";
@import "dragula";
/config/webpack.config.vendor.js
/*
After making changes to this file, you MUST re-build the vendor bundle
*/
var isDevBuild = process.argv.indexOf("--env.prod") < 0;
var path = require("path");
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var extractCSS = new ExtractTextPlugin("vendor.css");
var helpers = require("./helpers");
module.exports = {
devtool: "source-map",
resolve: {
extensions: ["", ".json", ".js"]
},
module: {
loaders: [
{
test: /\.json$/,
loaders: ["json-loader"],
include: helpers.root("node_modules")
},
{
test: /\.png(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=image/png&name=img/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.jpe?g(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=image/jpeg&name=img/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.gif(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=image/gif&name=img/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.ico(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=image/x-icon&name=img/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.woff2?(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=application/font-woff&name=fonts/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.ttf(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=application/octet-stream&name=fonts/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.eot(\?.*$|$)/,
loader: "url-loader?limit=10000&name=fonts/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.svg(\?.*$|$)/,
loader: "url-loader?limit=10000&mimetype=image/svg+xml&name=img/[name].[ext]?[hash]",
include: helpers.root("node_modules")
},
{
test: /\.scss(\?|$)/,
loader: extractCSS.extract(["css", "resolve-url", "sass?sourceMap"]),
include: helpers.root("node_modules")
},
{
test: /\.css(\?|$)/,
loader: extractCSS.extract(["css"]),
include: helpers.root("node_modules")
}
]
},
entry: {
vendor: [
"@angular/common",
"@angular/compiler",
"@angular/core",
"@angular/flex-layout",
"@angular/forms",
"@angular/http",
"@angular/material",
"@angular/platform-browser",
"@angular/platform-browser-dynamic",
"@angular/router",
"angular2-contextmenu",
"angular2-grid",
"angular2-modal",
"angular2-modal/plugins/bootstrap",
"angular2-notifications",
"angular2-universal",
"angular2-universal-polyfills",
"angular2-universal-polyfills/browser",
"angular2-uuid",
"animate.css/animate.min.css",
"ansi-html",
"ansi-regex",
"awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css", // scss does not define variables it uses
"bootstrap",
"bootstrap/scss/bootstrap.scss",
"bootstrap-colorpicker",
"bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css",
"bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css",
"bootstrap-select/dist/css/bootstrap-select.css",
"bootstrap-select/dist/css/bootstrap-select.min.css",
"d3",
"dragula",
"es6-promise",
"es6-shim",
"event-source-polyfill",
"font-awesome/scss/font-awesome.scss",
// glyphicions-halflings is incomplete, has references to non-existing files (must be overwritten)
// "glyphicons-halflings/css/glyphicons-halflings.css",
"html-entities",
"jquery",
"jquery.animate-number",
"jquery-slimscroll",
"jquery-slimscroll",
"jquery-ui",
"jquery-ui/ui/widgets/sortable",
"lodash",
"moment",
"moment-timezone",
"ng2-bootstrap",
"ng2-cookies",
"ng2-cookies",
"ng2-cookies/ng2-cookies",
"ng2-datetime",
"ng2-datetime-picker",
"ng2-dnd",
"ng2-dnd/bundles/style.css",
"ng2-dragula",
"ng2-dragula/ng2-dragula",
"ng2-file-upload",
"ng2-nouislider",
"ng2-pagination",
"ng2-select2",
"ng2-table",
"nouislider",
"nouislider/distribute/nouislider.css",
"nouislider/distribute/nouislider.min.css",
"nvd3",
"nvd3/build/nv.d3.css",
"pace/themes/pace-theme-flash.css",
"primeng/primeng.js",
"primeng/resources/primeng.min.css",
"primeng/resources/themes/bootstrap/theme.css",
"querystring",
"rxjs",
"strip-ansi",
"zone.js"
]
},
output: {
path: helpers.root("wwwroot", "dist"),
filename: "[name].js",
library: "[name]_[hash]"
},
plugins: [
extractCSS,
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
// jquery: "jquery",
"window.jQuery": "jquery",
Tether: "tether",
"window.Tether": "tether",
Hammer: "hammerjs/hammer",
Shuffle: "shufflejs",
d3: "d3",
Rickshaw: "rickshaw",
nv: "nvd3",
Raphael: "webpack-raphael",
"window.Raphael": "webpack-raphael",
Skycons: "skycons/skycons",
Dropzone: "dropzone"
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DllPlugin({
path: helpers.root("wwwroot", "dist", "[name]-manifest.json"),
name: "[name]_[hash]",
context: helpers.root("node_modules")
}),
// HACK: make webpack exit with != 0 error code on error (when not in HMR/dev) https://github.com/webpack/webpack/issues/708
function () {
this.plugin("done", function (stats) {
if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf("--watch") === -1) {
console.log(stats.compilation.errors);
process.exit(1); // or throw new Error("webpack build failed.");
}
});
}
].concat(isDevBuild ? [] : [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
])
};
我的客户端配置包含以下部分:
/config/webpack.dev.js
console.log("----> Development");
var webpackMerge = require('webpack-merge');
var commonConfig = require('./webpack.common.js');
var commonClientConfig = require('./webpack.common.client.js');
var webpack = require('webpack');
var clientBundleConfig = webpackMerge(commonConfig, commonClientConfig, {
plugins: [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin(
// the following did not work, but using no arguments works fine
/*{
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(helpers.root('wwwroot','dist'), '[resourcePath]') // Point sourcemap entries to the original file locations on disk
}*/)
]
});
module.exports = [clientBundleConfig];
/config/webpack.common.js
var helpers = require('./helpers');
var webpack = require("webpack");
module.exports = {
resolve: {
extensions: ['', '.js', '.ts'],
root: [
helpers.root('app')
]
},
output: {
publicPath: '/dist/', // Webpack dev middleware, if enabled, handles requests for this URL prefix
filename: '[name].js',
chunkFilename: '[id].chunk.js'
},
module: {
loaders: [
{
test: /\.ts$/,
include: [
helpers.root('app')
],
loaders: ['awesome-typescript-loader', 'angular2-template-loader']
},
{
test: /\.html$/, // mostly angular templates
include: helpers.root('app'),
loader: 'html'
},/*
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?.*$|$)/,
include: [
helpers.root('node_modules','font-awesome'),
helpers.root('node_modules','bootstrap')
],
loader: 'file?name=vendor-missing/[name].[hash].[ext]'
},*/
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?.*$|$)/,
include: [
helpers.root('app'),
], // new
loader: 'file?name=assets/[name].[hash].[ext]'
},
{
test: /\.scss$/,
include: helpers.root('app'), // new
// IMPORTANT: Sass/libsass do not provide url rewriting, all linked assets must be relative to the output. css loader can process generated css though
/*loader: ExtractTextPlugin.extract(
'style', // The backup style loader
'css?sourceMap!sass?sourceMap'
)
*/
// resolve-url needs source map to operate correctly, but then there's this issue of sourcemap urls not being generated correctly https://github.com/webpack/css-loader/issues/232
// loaders: ['raw', 'css', 'resolve-url', 'sass?sourceMap']
loaders: ['to-string','css', 'resolve-url', 'sass?sourceMap']
// loader: ExtractTextPlugin.extract(['css', 'resolve-url', 'sass?sourceMap']) // no hot module replacement!
},{
test: /\.css$/,
include: helpers.root('app'),
loader: 'to-string!css!resolve-url'
// loader: ExtractTextPlugin.extract(['css','resolve-url']) // no HMR/hot
}
]
},
htmlLoader: {
ignoreCustomFragments: [/\{\{.*?}}/],
// root: helpers.root(),
root: helpers.root('app'),
attrs: ['img:src', 'link:href']
},
plugins: [
// plugins must always be defined, even if empty
// https://github.com/aspnet/JavaScriptServices/issues/358
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
// jquery: 'jquery',
'window.jQuery': 'jquery',
Tether: 'tether',
'window.Tether': 'tether',
Hammer: 'hammerjs/hammer',
Shuffle: 'shufflejs',
d3: 'd3',
Rickshaw: 'rickshaw',
nv: 'nvd3',
Raphael: 'webpack-raphael',
'window.Raphael': 'webpack-raphael',
Skycons: 'skycons/skycons',
Dropzone: 'dropzone'
})
// don't do workaround/hack for failed webpack here - dev might benefit from being able to keep service running
]
};
/config/webpack.common.client.js
const CopyWebpackPlugin = require('copy-webpack-plugin');
var helpers = require('./helpers');
var webpack = require('webpack');
var commonClient = {
entry: {
'main-client': helpers.root('app', 'boot-client.ts')
},
output: {
path: helpers.root('wwwroot', 'dist')
},
plugins: [
// NOTE: each target folder must already exist!
// We must copy these assets because they are referenced as hardcoded strings (without url or require). webpack cannot resolve these dependencies
new CopyWebpackPlugin([{
context: helpers.root('app', 'assets', 'img'),
from: helpers.root('app', 'assets', 'img', '**', '*'),
to: helpers.root('wwwroot', 'dist', 'assets', 'img')
}],
{
debug: 'warning',
copyUnmodified: false // TODO: set to true if not all files are watched
}),
// _Layout.cshtml relies on wwwroot/dist/assets/img/brand_small_black.ico
new CopyWebpackPlugin([{
context: helpers.root('app', 'assets', 'img'),
from: helpers.root('app', 'assets', 'img', 'logo', 'brand_small_black.ico'),
to: helpers.root('wwwroot', 'dist', 'assets', 'img', 'brand_small_black.ico')
}],
{
debug: 'warning',
copyUnmodified: false // TODO: set to true if not all files are watched
}),
new webpack.DllReferencePlugin({
context: helpers.root('node_modules'), // (absolute path) context of requests in the manifest (or content property)
manifest: require('../wwwroot/dist/vendor-manifest.json') // (object): an object containing content and name
// manifest: require(helpers.root('wwwroot', 'dist', 'vendor-manifest.json'))
}),
]
};
module.exports = commonClient;