Is it possible to get the CSS for a Vue component, and attach it as a string to a component when building a library for use at runtime?
vue-cli-service build --mode production --target lib --name components src/index.ts
I currently achieve this for some custom js using a custom block:
vue.config.js:
...
rules: [
{
resourceQuery: /blockType=client-script/,
use: './client-script-block',
},
],
},
...
client-script-block.js:
module.exports = async function () {
return `export default function (Component) {
Component.options.__client_script = ${JSON.stringify(this.resourcePath)};
}`;
};
which then exposed the string in the Vue app that uses the library. But achieving the same thing with CSS doesn't seem to play ball.
You could take a look at this CSS Extraction modules from VueLoader, that extracts the CSS from specific file or files, and stores it in a custom file, that you could then load dynamically in runtime, like:
Install:
npm install -D mini-css-extract-plugin
// webpack.config.js
var MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
// other options...
module: {
rules: [
// ... other rules omitted
{
test: /\.css$/,
use: [
process.env.NODE_ENV !== 'production'
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
// ... Vue Loader plugin omitted
new MiniCssExtractPlugin({
filename: 'style.css'
})
]
}
Reference: https://vue-loader.vuejs.org/guide/extract-css.html#webpack-4:
Another approach:
// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// other options...
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
extractCSS: true
}
}
]
},
plugins: [
new ExtractTextPlugin("style.css")
]
}
Reference: https://vue-loader-v14.vuejs.org/en/configurations/extract-css.html
Also here you have a complete guide for extracting the CSS from a SSR (Server Side Rendered) apps: https://ssr.vuejs.org/guide/css.html#enabling-css-extraction
Related
I have babel loader in the library. Still after I add the library to the react application while yarn serve, I get the above error.
This is the webpack.dev.config.js (required in the webpack.config.js) in library-
//webpack.dev.config.js
const babelRCPath = require('#appfabric/infra-scripts').getConfigPath('babel', 'plugin');
const babelRCGenerator = require(babelRCPath);
const babelRC = babelRCGenerator([]);
module.exports = {
{
BaseModule: `${process.cwd()}/src/BaseModule`,
BaseObject: `${process.cwd()}/src/BaseObject`,
BaseWidget: `${process.cwd()}/src/widgets/BaseWidget`,
HOCWidget: `${process.cwd()}/src/widgets/HOCWidget`,
PortalWidget: `${process.cwd()}/src/widgets/PortalWidget`,
BaseActivator: `${process.cwd()}/src/application/BaseActivator`,
CorePlugin: `${process.cwd()}/src/application/CorePlugin`,
BaseAppDelegate: `${process.cwd()}/src/application/appdelegates/BaseAppDelegate`,
EmbeddedAppDelegate: `${process.cwd()}/src/default/appdelegates/embedded/EmbeddedAppDelegate`,
ActionType: `${process.cwd()}/src/application/appdelegates/actions/ActionType`,
types: `${process.cwd()}/src/application/appdelegates/actions/types`,
CommandActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandActionType`,
CommandForResponseActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandForResponseActionType`,
PluginRegistryService: `${process.cwd()}/src/default/PluginRegistryService`,
},
mode: 'development',
externals: [
'dcl',
'react',
'react-dom',
'prop-types',
'pubsub',
'semver',
'#appfabric/ui-profiler',
].map(
// Add this regex to each entry to ensure we don't miss any imports like 'web-shell-core/...`
(value) => new RegExp(`^(${value})((\\\\|/|!).+)?$`),
),
output: {
path: `${process.cwd()}/build/dist`,
filename: '[name].js',
library: 'web-shell-core',
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: babelRC,
},
},
],
},
};
This is the webpack.config.js
const developmentConfig = require('./webpack.dev.config.js');
module.exports = merge(developmentConfig, {
mode: 'production',
output: {
filename: '[name].min.js',
chunkFilename: '[name].min.js',
},
});
First I add a new file Secure.jsx(having the tags) in the library. I do npm install --save <path-to-library> on my application. After I do yarn install. Then I can see the new file Secure.jsx in the node modules in the application. When I try to run the application, I get the error.
Please let me know what am I missing and also which side(library / application) I have to add the code.
You can view my full config here
I think you also need to add this
resolve: {
modules: [
path.resolve('./node_modules')
]
},
Then import like this
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";
I am new to React world, and I'm trying to integrate it in a new project that uses ASP MVC .net.
I want to use React.js with the create react app, not interested in the React.net integration.
I have seen a couple examples that don't use the CRA command, instead they configure the build set up themselves (webpack, babel, etc), I was trying that approach, but I'm worried that if the project grows I will lose track of updates, etc.
In that example, you need to add whatever the output of the webpack bundled file is into your index.cshtml.
<div id="root"></div>
#section scripts {
<script src="~/Scripts/React/dist/bundle.js"></script>
}
But when I use the CRA command I don't have access to that file during development, only when I build for production.
I'm a little lost here, what is the best way of achieving what I need with CRA without ejecting?
I really appreciate any help :)
I don't think it is possible to do what you want (and I wanted too) with CRA and I believe the complexity you will end up after ejecting is too high to be manageable.
My starting point: a big ASP MVC application running an Angular.js front-end within a single MVC Controller/View (the default index page).
My goal: stop growing the Angular.js app and develop new functionality with React whenever possible, i.e. when it is independent of existing UI; let's call it new modules. I still need to keep everything within the same MVC app because it provides authentication and authorization among other things.
The solution: a custom (with respect to CRA) webpack build toolchain whose starting point is the youtube example you provided. Thanks to this other tutorial, I have been able to add hot reload and after a few hours of trial and error I added loaders for css, images and fonts. The bundled result is for sure less optimal than the outcome of CRA, but it coexists with the old Angular.js so I believe it is good enough.
Here is some code.
webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
const webpack = require('webpack');
const PUBLIC_PATH = 'Scripts/react/dist';
module.exports = (env, arg) => {
const isDevelopment = arg.mode === 'development';
const fileLoaderName = file => {
if (isDevelopment)
return '[folder]/[name].[ext]';
return '[folder]/[name].[ext]?[contenthash]';
};
return {
entry: './app.js',
watch: isDevelopment,
devtool: isDevelopment ? 'source-map' : undefined,
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
'babel-loader',
{
loader: 'eslint-loader',
options: {
fix: true
}
}
],
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: fileLoaderName,
publicPath: PUBLIC_PATH,
postTransformPublicPath: p => `__webpack_public_path__ + ${p}`
}
}
]
},
{
test: /\.(woff|woff2|ttf|otf|eot)$/i,
use: [
{
loader: 'file-loader',
options: {
name: fileLoaderName,
publicPath: PUBLIC_PATH,
postTransformPublicPath: p => `__webpack_public_path__ + ${p}`
}
}
]
}
],
},
plugins: [
new webpack.ProgressPlugin(),
new WebpackNotifierPlugin(),
new BrowserSyncPlugin(),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({ filename: "bundle.css" })
],
resolve: {
extensions: ['*', '.js', '.jsx']
},
output: {
path: __dirname + '/dist',
publicPath: '/',
filename: 'bundle.js'
},
}
};
.babelrc
{
"presets": [
"#babel/preset-env",
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-transform-runtime"
]
}
.eslintrc
{
"extends": [
"plugin:react-app/recommended",
"prettier"
],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": ["error"],
"quotes": [
"error",
"single",
{ "allowTemplateLiterals": true }
]
}
}
.prettierrc
{
"singleQuote": true
}
package.json
...
"scripts": {
"start": "webpack --mode development",
"build": "webpack --mode production",
...
},
There are still a few useful things that are missing and I plan to add in the future, like css modules and other css optimizations, but I think it's not going to be to difficult.
I'm super new to webpack and I do not seem to find a way to bundle JS files as I did with Gulp in a very easy way. I've been searching a bit but didn't find any straight answer to it.
Right now I'm creating two minified files by using in my package.json file, but I would love to have a single one instead:
"scripts": {
"stand-alone": "concurrently 'webpack --config=webpack.config.js src/whatever.vue demos/build.min.js --output-library=whatever1' 'webpack --config=webpack.config.js src/whatever2.js demos/mixin.min.js --output-library=whatever2'",
},
Then my webpack.config.js looks like this:
const webpack = require('webpack');
module.exports = {
resolve: {
alias: {
'vue$': 'vue/dist/vue.js'
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: 'vue-style-loader!css-loader!sass-loader',
js: 'babel-loader'
}
}
},
{
test: /\.js$/,
use: {
loader: 'babel-loader',
}
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
}
})
],
};
I believe you are looking for entry points.
In your webpack.config.js module exports object:
Define the entry property:
entry: {
app: ['./path/to/file.js', './path/to/file2.js'],
},
Define the output property:
output: {
path: '/path/to/assets', // ex. '../../wwwroot/dist'
filename: '[name].js', // Substitutes [name] with the entry name, results in app.js
publicPath: '/'
},
Change your script to:
"scripts": {
"stand-alone": "webpack --config=webpack.config.js",
},
If you are using Vue + Webpack, I recommend that you take a look to vue-cli and generate a project using the webpack template. It is more advanced, but you can see the documentation and get an idea of what you are missing.
Run the following:
npm install -g vue-cli // install vue cli globally
vue init webpack my-project // create a sample project
If you want to generate multiple output files, you can have more than one entry point like so:
entry: {
app: ['./path/to/file.js', './path/to/file2.js'],
mixins: './path/to/mixins.js',
vendors: ['./path/to/vendor.js', './path/to/vendor2.js']
},
This will write to disk ./path/to/assets/app.js, ./path/to/assets/mixins.js, /path/to/assets/vendors.js.
First. I know questions like this were asked, but I am missing something to understand them. I am trying to compile scss to css. And I would like webpack to basically do the same as sass app.scss : app.css. I tried to configure it using extract-text-webpack-plugin, but I am doing something wrong or missing smth.
It worked if I include(app.scss) in app.js but this makes no sense because if anyone has disabled JavaScript the styles won't work.
This is my webpack.config.js file. I have no idea how to do it.
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var jsConfig = {
entry: "./_dev/scripts/app.js",
output: { filename: "./scripts/bundle.js" },
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
}
};
var scssConfig = {
entry: "./_dev/scss/app.scss",
output: { filename: "./content/app.css" },
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin({filename:"./_dev/scss/app.scss"}),
]
};
var config = [scssConfig, jsConfig];
module.exports = config;
Edit: I also found this. This series would have helped with all my questions so if you have similar questions make sure to read it before asking!
https://codeburst.io/simple-beginner-guide-for-webpack-2-0-from-scratch-part-v-495dba627718
You need to include your app.scss for webpack to be able to find your scss references because webpack will traverse your project and apply loaders to all files it can find through references starting from app.js recursively down. If you don't have references to app.scss somewhere in the project webpack can't find it and it won't build it. So in the entry of you project (assume it is app.js) you need to do this:
import 'relative/path/to/styles/app.scss';
But it doesn't mean that those who don't have js enabled won't receive your styles. You need to include app.scss only for the build phase of your project, after that your styles will be included in html and will be loaded even for those without js enabled.
webpack concepts section explains how webpack finds dependencies based on your entry point building its internal graph of dependencies.
Update:
There is a way that allows you to not add your app.scss in your js. You can include multiple files in your entry object in your webpack config. Here is an example of how configuration might look in your case:
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var config = {
entry: {
main: [
"./_dev/scripts/app.js",
"./_dev/scss/app.scss"
],
},
output: {
path: './scripts',
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
},
{
test: /\.(css|scss)/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ['css-loader', 'sass-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin("./_dev/scss/app.scss"),
]
};
module.exports = config;
More information available on SO question webpack-multiple-entry-points-sass-and-js.
You also have incorrect configuration of ExtractTextPlugin in webpack. You are placing the whole path in the option for filename, which is not correct. In your case it should look like this:
plugins: [
new ExtractTextPlugin("./_dev/scss/app.css"),
]
So i am trying to figure out how to use webpack to replace our current brunch build process. Basically we have an angular 1 app which doesnt utilise requires or imports at all and I want to have webpack just concat+transpile the files (there are both coffee and sass files and ill need to be able to watch and create source maps using the usual settings). This angular app is sitting inside another application which is using webpack extensively.
What is the simplest way to accomplish this? Is this even possible without the app using any form of javascript modules?
Here is my current config:
var webpack = require( "webpack" );
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require("path");
var glob = require("glob");
const exportConfig = {
entry: {
app: glob.sync('./front-end/applications/core/app/**/*.coffee'),
vendor: ['angular']
},
output: {
filename: "app.bundle.js",
path: path.join( __dirname, "../www_root/build" ),
},
debug: true,
module: {
loaders: [
{
test: /\.coffee$/,
loader: "coffee-loader"
},
{
test: /\.sass$/,
loaders: ["style", "css", "sass"]
},
{
test: /\.(jsx|es6)/,
exclude: /(node_modules|www_root\/bower)/,
loader: "babel",
},
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js"),
new ExtractTextPlugin("[name].css", {
allChunks: true
}),
]
}
module.exports = exportConfig
I basically just get an output file with an error for each of the files obviously:
(function webpackMissingModule() { throw new Error("Cannot find module \"./front-end/applications/core/app/components/app/module.coffee\""); }());
Thanks!